How can I create an Access Database at runtime in C#?
The first thing you need to do is get a COM reference to the Microsoft ADO Ext. X.X for DDL and Security. The X.X represents whatever version you happen to have on your machine. Mine used to be version 2.7, but with Visual Studio 2008, it was updated to 6.0.
alt text http://blog.jrpsoftware.com/content/binary/WindowsLiveWriter/CreateanAccessDatabaseinC_10DDD/AddReference_2.png
Once you have added the reference, ADOX will be added to the using section of your code.
alt text http://blog.jrpsoftware.com/content/binary/WindowsLiveWriter/CreateanAccessDatabaseinC_10DDD/Using_2.png
Next you will want to create the catalog for the database. Insert the filename you wish into the following string and pass it to the CatalogClass.
CatalogClass cat = new CatalogClass();
string tmpStr;
string filename = "Sample.MDB";
tmpStr = "Provider=Microsoft.Jet.OLEDB.4.0;";
tmpStr += "Data Source=" + filename + ";Jet OLEDB:Engine Type=5";
cat.Create(tmpStr);
The next step is to create the table and columns for your database. This is a pretty straight forward operation as shown in the example below.
Table nTable = new Table();
nTable.Name = "PersonData";
nTable.Columns.Append("LastName", DataTypeEnum.adVarWChar, 25);
nTable.Columns.Append("FirstName", DataTypeEnum.adVarWChar, 25);
nTable.Columns.Append("Address 1", DataTypeEnum.adVarWChar, 45);
nTable.Columns.Append("Address 2", DataTypeEnum.adVarWChar, 45);
nTable.Columns.Append("City", DataTypeEnum.adVarWChar, 25);
nTable.Columns.Append("State", DataTypeEnum.adVarWChar, 2);
nTable.Columns.Append("Zip", DataTypeEnum.adVarWChar, 9);
cat.Tables.Append(nTable);
The final step is very important or you will get error when you close your application. Once the all the tables and columns have been added, you will need to release the com objects properly and in the proper order.
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(nTable);
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(cat.Tables);
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(cat.ActiveConnection);
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(cat);
That is it. You should now have a Access Database that you can write to. Hope this helps.
Reference: John Russell Plant - Create an Access Database in C#
Create a blank access database and store it in your resource files.
Now whenever you want to use it, fetch that database from your resources and copy it to wherever you want, rename it to whatever you want and execute your database setup script to create default tables and load values in them.
Try:
using ADOX; //Requires Microsoft ADO Ext. 2.8 for DDL and Security
using ADODB;
public bool CreateNewAccessDatabase(string fileName)
{
bool result = false;
ADOX.Catalog cat = new ADOX.Catalog();
ADOX.Table table = new ADOX.Table();
//Create the table and it's fields.
table.Name = "Table1";
table.Columns.Append("Field1");
table.Columns.Append("Field2");
try
{
cat.Create("Provider=Microsoft.Jet.OLEDB.4.0;" + "Data Source=" + fileName + "; Jet OLEDB:Engine Type=5");
cat.Tables.Append(table);
//Now Close the database
ADODB.Connection con = cat.ActiveConnection as ADODB.Connection;
if (con != null)
con.Close();
result = true;
}
catch (Exception ex)
{
result = false;
}
cat = null;
return result;
}
http://zamirsblog.blogspot.com/2010/11/creating-access-database.html
This article from John Russell Plant explains how you'd do it in specific detail with code samples. There are three steps:
Create the catalog.
Create the tables.
Release the relevant COM objects.
static void IF_EXISTS_DELETE_AND_CREATE(string cn)
{
//cn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source =";
//cn += AppDomain.CurrentDomain.BaseDirectory.ToString() + "test.mdb";
try
{
OleDbConnection connection = new OleDbConnection(cn);
object[] objArrRestrict;
objArrRestrict = new object[] { null, null, null, "TABLE" };
connection.Open();
DataTable schemaTable = connection.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, objArrRestrict);
connection.Close();
string[] list;
if(schemaTable.Rows.Count > 0)
{
list = new string[schemaTable.Rows.Count];
int i = 0;
foreach (DataRow row in schemaTable.Rows)
{
list[i++] = row["TABLE_NAME"].ToString();
}
for ( i = 0; i < list.Length; i++)
{
if(list[i] == "TEMP")
{
string deletedl = "DROP TABLE TEMP";
using (OleDbConnection conn = new OleDbConnection(cn))
{
using (OleDbCommand cmd = new OleDbCommand(deletedl, conn))
{
conn.Open();
cmd.ExecuteNonQuery();
conn.Close();
}
}
break;
}
}
}
string ddl = "CREATE TABLE TEMP (USERID INTEGER NOT NULL,[ADATE] TEXT(20), [ATIME] TEXT(20))";
using(OleDbConnection conn = new OleDbConnection(cn))
{
using(OleDbCommand cmd = new OleDbCommand(ddl, conn))
{
conn.Open();
cmd.ExecuteNonQuery();
conn.Close();
}
}
}
catch (System.Exception e)
{
string ex = e.Message;
}
}
Related
Sorry for my spelling, I create so C# form application with local database. I created simple code which worked fine:
SqlCeConnection conn = new SqlCeConnection("Data Source = 4.sdf");
Microsoft.Office.Interop.Excel.Application xls = new Microsoft.Office.Interop.Excel.Application();
Workbook vb = xls.Workbooks.Add(XlSheetType.xlWorksheet);
Worksheet vs = (Worksheet)xls.ActiveSheet;
String t = "SELECT d.[regnr], d.[dalisid],d.[kiekis],d.[kaina] FROM [bilietas] AS b, [dalispard] AS d WHERE b.[regnr]=d.[regnr]";
SqlCeCommand cmd = new SqlCeCommand(t, conn);
conn.Open();
SqlCeDataReader rdr = cmd.ExecuteReader();
int i=2;
object aa, bb, cc, dd;
vs.Cells[1, 1] = "Reg. NR.";
vs.Cells[1, 2] = "Dalies ID";
vs.Cells[1, 3] = "Kiekis";
vs.Cells[1, 4] = "Kaina";
try
{
while (rdr.Read())
{
aa = rdr.GetValue(0);
bb = rdr.GetValue(1);
cc = rdr.GetValue(2);
dd = rdr.GetValue(3);
vs.Cells[i, 1] = aa.ToString();
vs.Cells[i, 2] = bb.ToString();
vs.Cells[i, 3] = cc.ToString();
vs.Cells[i, 4] = dd.ToString();
i++;
}
}
finally { conn.Close(); rdr.Close(); }
xls.Visible = true;
it bugged and started write emty cells on excel file when I edited input button for refreshing datagridview when input to table are saved by adding:
string eilute = "SELECT * FROM bilietas";
SqlCeCommand cmdd = new SqlCeCommand(eilute, conn);
conn.Open();
try
{
dt.Load(cmdd.ExecuteReader());
BindingSource bs = new BindingSource();
bs.DataSource = dt;
bilietasDataGridView.DataSource = bs;
MessageBox.Show("Atlikta", "Atlikta", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
finally { conn.Close(); }
So I really have no idea why it not working anymore.
Using Excel interop is not the best idea in your case - it is slow and requires Excel installed. Try other approach - OleDbConnection way. You can write data to Excel worksheet using plain SQL INSERT command. Create OleDbConnection object with the following connection string:
"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=SAMPLE.XLSX;Extended Properties=\"Excel 12.0 XML\";"
After that create new OleDbCommand with text like this:
"insert into [YOR_WORKBOOK_NAME$] ([COLUMN_NAME]) values ('Sample text')"
Execute command with ExecuteNonQuery method. Repeat this command with different values to insert many rows to your workbook. This method is much faster than interop approach.
I'm trying to write data back into a file on Unidata, after the contents have been adjusted in a datagridview.
I've tried various option based around the code below, but with no luck.
Within the foreach section I want to update my file.
The file consists of 10 single value attributes.
I tried fl.write(),but get an error relating to writing to a null value...
try
{
DataTable modifiedTable = m_DS.Tables[0].GetChanges(DataRowState.Modified);
if (modifiedTable.Rows.Count > 0)
{
U2Connection con = GetConnection();
Console.WriteLine("Connected.................");
UniSession lUniSession = con.UniSession;
UniFile fl = lUniSession.CreateUniFile("myTableName");
UniDynArray udr3 = new UniDynArray(lUniSession);
foreach (DataRow item in modifiedTable.Rows)
{
}
con.Close();
}
}
Thank you for using UniObjects’s API of U2 Toolkit for .NET (formerly known as standalone UO.NET).
Yesterday (June 10th, 2014) , we have Released U2 Toolkit for .NET v2.1.0. Main features of U2 Toolkit for .NET v2.1.0 is
Native Visual Studio Integration
For other features, see this link
http://blog.rocketsoftware.com/2014/05/access-nosql-data-using-sql-syntax-u2-toolkit-net-v2-1-0-beta/
Can you please try the same code ( 10 single value attributes) using SELECT and UPDATE. For your information, SELECT and UPDATE behind the scene calls UniFile Read and Write. These Samples are part of the installation. Go to these directories.
C:\Program Files (x86)\Rocket Software\U2 Toolkit for .NET\U2 Database Provider\samples\C#\UniData\NativeAccess\Select_SQL_Syntax
C:\Program Files (x86)\Rocket Software\U2 Toolkit for .NET\U2 Database Provider\samples\C#\UniData\NativeAccess\Update_SQL_Syntax
SELECT
private static void Select()
{
try
{
Console.WriteLine(Environment.NewLine + "Start...");
ConnectionStringSettingsCollection settings = ConfigurationManager.ConnectionStrings;
ConnectionStringSettings cs = settings["u2_connection"];
U2Connection lConn = new U2Connection();
lConn.ConnectionString = cs.ConnectionString;
lConn.Open();
Console.WriteLine("Connected...");
U2Command cmd = lConn.CreateCommand();
//ID,FNAME,LNAME : Single Value
//SEMESTER: Multi Value
//COURSE_NBR,COURSE_GRD: MS
cmd.CommandText = string.Format("SELECT ID,FNAME,LNAME,SEMESTER,COURSE_NBR,COURSE_GRD FROM STUDENT WHERE ID > 0 ORDER BY ID");
U2DataAdapter da = new U2DataAdapter(cmd);
DataSet ds = new DataSet();
da.Fill(ds);
Console.WriteLine(Environment.NewLine);
ds.WriteXml(Console.Out);
lConn.Close();
Console.WriteLine(Environment.NewLine + "End...");
Console.WriteLine(SUCCESS_MSG);
}
catch (Exception e2)
{
string lErr = e2.Message;
if (e2.InnerException != null)
{
lErr += lErr + e2.InnerException.Message;
}
Console.WriteLine(Environment.NewLine + lErr);
Console.WriteLine(FAIL_MSG);
}
}
Update
private static void Update_Using_DataSet()
{
try
{
Console.WriteLine(Environment.NewLine + "Start...");
ConnectionStringSettingsCollection settings = ConfigurationManager.ConnectionStrings;
ConnectionStringSettings cs = settings["u2_connection"];
U2Connection lConn = new U2Connection();
lConn.ConnectionString = cs.ConnectionString;
lConn.Open();
Console.WriteLine("Connected...");
U2Command cmd = lConn.CreateCommand();
//ID,FNAME,LNAME : Single Value
//SEMESTER: Multi Value
//COURSE_NBR,COURSE_GRD: MS
cmd.CommandText = string.Format("SELECT ID,FNAME,LNAME,SEMESTER,COURSE_NBR,COURSE_GRD FROM STUDENT WHERE ID={0} ORDER BY ID",ID);
U2DataAdapter da = new U2DataAdapter(cmd);
U2CommandBuilder builder = new U2CommandBuilder(da);
da.UpdateCommand = builder.GetUpdateCommand();
DataSet ds = new DataSet();
da.Fill(ds);
DataTable dt = ds.Tables[0];
DataRowCollection lDataRowCollection = dt.Rows;
int i = 1;
foreach (DataRow item in lDataRowCollection)
{
item["FNAME"] = item["FNAME"] + "3";// modify single value
item["SEMESTER"] = item["SEMESTER"] + "$";//modify multi-value
item["COURSE_GRD"] = item["COURSE_GRD"] + "$";
i++;
}
da.Update(ds);//use DataAdapter's Update() API
//print modified value
cmd.CommandText = string.Format("SELECT ID,FNAME,LNAME,SEMESTER,COURSE_NBR,COURSE_GRD FROM STUDENT WHERE ID={0} ORDER BY ID", ID); ;
//verify the change
U2DataAdapter da2 = new U2DataAdapter(cmd);
DataSet ds2 = new DataSet();
da2.Fill(ds2);
Console.WriteLine(Environment.NewLine);
ds2.WriteXml(Console.Out);
//close connection
lConn.Close();
Console.WriteLine(Environment.NewLine + "End...");
Console.WriteLine(SUCCESS_MSG);
}
catch (Exception e2)
{
Console.WriteLine(FAIL_MSG);
string lErr = e2.Message;
if (e2.InnerException != null)
{
lErr += lErr + e2.InnerException.Message;
}
Console.WriteLine(Environment.NewLine + lErr);
}
}
You will need to modify the UniDynArray (the record) for each row value in the table and then write the UniDynArray to the file and specific record id:
for (Int32 i=0; i < modifiedTable.Rows.Count; i++)
{
DataRow item = modifiedTable.Rows[i];
//Modify each attribute in the record from the rows in the table
udr3.Replace(i+1, (String)item[0]);
}
//Write the modified record to the file
fl.Write("MyRecordId", udr3);
The reason you got the null reference exception is because you didn't assign a value to fl.RecordId or fl.Record before calling fl.Write(). As you can see above, I prefer to use the overload of the Write method that takes record id and record data as parameters instead of setting the properties on the instance of UniFile.
Here's my situation. I'm designing a program that takes Excel files (which may be in csv, xls, or xlsx format) from a remote network drive, processes the data, then outputs and stores the results of that process. The program provides a listbox of filenames that are obtained from the remote network drive folder using the method detailed in the accepted answer here. Once the user selects a filename from the listbox, I want the program to find the file and obtain the information from it to do the data processing. I have tried using this method to read the data from the Excel file while in a threaded security context, but that method just fails without giving any kind of error. It seems to not terminate. Am I going about this the wrong way?
Edit - (Final Notes: I have taken out the OleDbDataAdapter and replaced it with EPPlus handling.)
I was able to scrub sensitive data from the code, so here it is:
protected void GetFile(object principalObj)
{
if (principalObj == null)
{
throw new ArgumentNullException("principalObj");
}
IPrincipal principal = (IPrincipal)principalObj;
Thread.CurrentPrincipal = principal;
WindowsIdentity identity = principal.Identity as WindowsIdentity;
WindowsImpersonationContext impersonationContext = null;
if (identity != null)
{
impersonationContext = identity.Impersonate();
}
try
{
string fileName = string.Format("{0}\\" + Files.SelectedValue, #"RemoteDirectoryHere");
string connectionString = string.Format("Provider=Microsoft.ACE.OLEDB.14.0; data source={0}; Extended Properties=Excel 14.0;", fileName);
OleDbDataAdapter adapter = new OleDbDataAdapter("SELECT * FROM Sheet1", connectionString);
DataSet ds = new DataSet();
adapter.Fill(ds, "Sheet1");
dataTable = ds.Tables["Sheet1"];
}
finally
{
if (impersonationContext != null)
{
impersonationContext.Undo();
}
}
}
Additional Edit
Now xlsx files have been added to the mix.
Third Party
Third party solutions are not acceptable in this case (unless they allow unrestricted commercial use).
Attempts - (Final Notes: Ultimately I had to abandon OleDb connections.)
I have tried all of the different connection strings offered, and I have tried them with just one file type at a time. None of the connection strings worked with any of the file types.
Permissions
The User does have access to the file and its directory.
Your connection string might be the issue here. As far as I know, there isn't 1 that can read all xls, csv, and xlsx. I think you're using the XLSX connection string.
When I read xls, i use the following connection string:
#"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + sFilePath + ";Extended Properties='Excel 8.0;HDR=YES;IMEX=1;'"
Having said that, I recommend using a 3rd party file reader/parser to read XLS and CSV since, from my experience, OleDbDataAdapter is wonky depending on the types of data that's being read (and how mixed they are within each column).
For XLS, try NPOI https://code.google.com/p/npoi/
For CSV, try http://www.codeproject.com/Articles/9258/A-Fast-CSV-Reader
For XLSX, try EPPlus http://epplus.codeplex.com/
I've had great success with the above libraries.
Is it really important that you use an OleDb interface for this? I've always done it with Microsoft.Office.Excel.Interop, to wit:
using System;
using Microsoft.Office.Interop.Excel;
namespace StackOverflowExample
{
class Program
{
static void Main(string[] args)
{
var app = new Application();
var wkbk = app.Workbooks.Open(#"c:\data\foo.xls") as Workbook;
var wksht = wkbk.Sheets[1] as Worksheet; // not zero-based!
for (int row = 1; row <= 100; row++) // not zero-based!
{
Console.WriteLine("This is row #" + row.ToString());
for (int col = 1; col <= 100; col++)
{
Console.WriteLine("This is col #" + col.ToString());
var cell = wksht.Cells[row][col] as Range;
if (cell != null)
{
object val = cell.Value;
if (val != null)
{
Console.WriteLine("The value of the cell is " + val.ToString());
}
}
}
}
}
}
}
As you will be dealing with xlsx extension, you should rather opt for the new connection string.
public static string getConnectionString(string fileName, bool HDRValue, bool WriteExcel)
{
string hdrValue = HDRValue ? "YES" : "NO";
string writeExcel = WriteExcel ? string.Empty : "IMEX=1";
return "Provider=Microsoft.ACE.OLEDB.12.0;" + "Data Source=" + fileName + ";" + "Extended Properties=\"Excel 12.0 xml;HDR=" + hdrValue + ";" + writeExcel + "\"";
}
Above is the code for getting the connection string. First argument expects the actual path for file location. Second argument will decide whether to consider first row values as column headers or not. Third argument helps decide whether you want to open the connection to create and write the data or simply read the data. To read the data set it to "FALSE"
public static ReadData(string filePath, string sheetName, List<string> fieldsToRead, int startPoint, int endPoint)
{
DataTable dt = new DataTable();
try
{
string ConnectionString = ProcessFile.getConnectionString(filePath, false, false);
using (OleDbConnection cn = new OleDbConnection(ConnectionString))
{
cn.Open();
DataTable dbSchema = cn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
if (dbSchema == null || dbSchema.Rows.Count < 1)
{
throw new Exception("Error: Could not determine the name of the first worksheet.");
}
StringBuilder sb = new StringBuilder();
sb.Append("SELECT *");
sb.Append(" FROM [" + sheetName + fieldsToRead[0].ToUpper() + startPoint + ":" + fieldsToRead[1].ToUpper() + endPoint + "] ");
OleDbDataAdapter da = new OleDbDataAdapter(sb.ToString(), cn);
dt = new DataTable(sheetName);
da.Fill(dt);
if (dt.Rows.Count > 0)
{
foreach (DataRow row in dt.Rows)
{
string i = row[0].ToString();
}
}
cn.Dispose();
return fileDatas;
}
}
catch (Exception)
{
}
}
This is for reading 2007 Excel into dataset
DataSet ds = new DataSet();
try
{
string myConnStr = "";
myConnStr = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=MyDataSource;Extended Properties=\"Excel 12.0;HDR=YES\"";
OleDbConnection myConn = new OleDbConnection(myConnStr);
OleDbCommand cmd = new OleDbCommand("select * from [Sheet1$] ", myConn);
OleDbDataAdapter adapter = new OleDbDataAdapter();
adapter.SelectCommand = cmd;
myConn.Open();
adapter.Fill(ds);
myConn.Close();
}
catch
{ }
return ds;
My application is a winform app that relies on a database. At startup of the application it connects to an SQL Database on the server and put this information in a DataSet/DataTable.
If for some reason the database on the server is not accessible, the application has a built in failover and it will get its information from the local database.
If, in a normal scenario, I start the tool it will read from the sql database and if it has been updated on the server (a seperate snippet checks this), it should make sure the local database is up to date and this is where the problem starts.. (see below)
This part works fine and is added as context - this is where we connect to the SQL Database
public static DataSet dtsTableContents;
public static DataTable CreateDatabaseSQLConnection()
{
try
{
string strSqlConnectionString = "Data Source=MyLocation;Initial Catalog=MyCatalog;User=MyUser;Password=MyPassword;";
SqlCommand scoCommand = new SqlCommand();
scoCommand.Connection = new SqlConnection(strSqlConnectionString);
scoCommand.Connection.Open();
string strQueryToTable = "SELECT * FROM " + strTableName;
dtsTableContents = new DataSet();
SqlCommand scmTableInformation = new SqlCommand(strQueryToTable, scnConnectionToDatabase);
SqlDataAdapter sdaTableInformation = new SqlDataAdapter(scmTableInformation);
scnConnectionToDatabase.Open();
sdaTableInformation.Fill(dtsTableContents, strTableName);
DataTable dttTableInformation = dtsTableContents.Tables[strTableName];
scnConnectionToDatabase.Close();
return dttTableInformation;
}
catch
{
return null;
}
}
This snippet is part of the failover method that reads from my local database...
This part works fine and is added as context - this is where we connect to the MDB Database
public static DataTable CreateDatabaseConnection()
{
try
{
string ConnectionString = #"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=MyLocation;Persist Security Info=True;JET OLEDB:Database Password=MyPassword;"
odcConnection = new OleDbConnection(ConnectionString);
odcConnection.Open();
string strQueryToTable = "SELECT * FROM " + strTableName;
DataSet dtsTableContents = new DataSet();
OleDbCommand ocmTableInformation = new OleDbCommand(strQueryToTable, ocnConnectionToDatabase);
OleDbDataAdapter odaTableInformation = new OleDbDataAdapter(ocmTableInformation);
ocnConnectionToDatabase.Open();
odaTableInformation.Fill(dtsTableContents, strTableName);
DataTable dttTableInformation = dtsTableContents.Tables[strTableName];
ocnConnectionToDatabase.Close();
return dttTableInformation;
}
catch
{
return null;
}
}
From my CreateDatabaseSQLConnection() I have a DataSet. This DataSet is verified to contain all the information from the server database. Now I have been googling around and found myself trying to use this code to update the local database based on this article:
http://msdn.microsoft.com/en-us/library/system.data.common.dataadapter.update(v=vs.71).aspx
public static void UpdateLocalDatabase(string strTableName)
{
try
{
if (CreateDatabaseConnection() != null)
{
string strQueryToTable = "SELECT * FROM " + strTableName;
OleDbDataAdapter odaTableInformation = new OleDbDataAdapter();
odaTableInformation.SelectCommand = new OleDbCommand(strQueryToTable, odcConnection);
OleDbCommandBuilder ocbCommand = new OleDbCommandBuilder(odaTableInformation);
odcConnection.Open();
odaTableInformation.Update(dtsTableContents, strTableName);
odcConnection.Close();
}
}
catch { }
}
This snippet runs error-free but it does not seem to change anything. Also the time it takes to run this step takes like milliseconds and I would think this to take longer.
I am using the DataSet I obtained from my SQL Connection, this DataSet I am trying to write to my local database.
Might it be the fact that this is a DataSet from an SQL connection and that I can't write this to my mdb connection via my OleDbAdapter or am I just missing the obvious here?
Any help is appreciated.
Thanks,
Kevin
For a straight backup from the external database to the internal backup
I've just been messing around with an sdf and a server based sql database and it has worked.. It's not by all means the finished product but for one column I've got the program to read from the external database and then write straight away to the local .sdf in around 15 lines of code
SqlConnection sqlCon = new SqlConnection( ExternalDatabaseConnectionString );
SqlCeConnection sqlCECon = new SqlCeConnection( BackUpConnectionString );
using ( sqlCon )
{
using ( sqlCECon )
{
sqlCon.Open( );
sqlCECon.Open( );
SqlCommand get = new SqlCommand( "Select * from [TableToRead]", sqlCon );
SqlCeCommand save = new SqlCeCommand( "Update [BackUpTable] set InfoColumn = #info where ID = #id", sqlCECon );
SqlDataReader reader = get.ExecuteReader( );
if ( reader.HasRows )
{
reader.Read( );
save.Parameters.AddWithValue("#id", reader.GetString(0));
save.Parameters.AddWithValue( "#info", reader.GetString( 1 ));
save.ExecuteNonQuery( );
}
}
}
For one row of a database, backing up one column, it works, I'm assuming you will have some sort of auto incremented key like ID?
I think a first step would be to reduce your reliance on static methods and fields.
If you look at your UpdateLocalDatabase method you'll see that you are passing in strTableName which is used by that method but a method that UpdateLocalDatabase calls (CreateDatabaseConnection) refers to a different global static variable named the same. Most likely the two strTableName variables contain different values and you are not seeing that they are not the same variable.
Also you are trying to write out the global static data set dtsTableContents in UpdateLocalDatabase but if you then look at CreateDatabaseConnection it actually creates a local version of that variable -- again, you have two variables named the same thing where one is global and one is local.
I suspect that the two variables of dtsTableContents is the problem.
My suggestion, again, would be to not have any static methods or variables and, for what you're doing here, try not to use any global variables. Also, refactor and/or rename your methods to match more what they are actually doing.
After endlessly trying to use the DataAdapter.Update(Method) I gave up.. I settled for using an sdf file instead of an mdb.
If I need to update my database, I remove the local database, create a new one, using the same connectionstring. Then I loop over the tables in my dataset, read the column names and types from it and create tables based on that.
After this I loop over my dataset and insert the contents of my dataset which I filled with the information from the server. Below is the code, this is just 'quick and dirty' as a proof of concept but it works for my scenario.
public static void RemoveAndCreateLocalDb(string strLocalDbLocation)
{
try
{
if (File.Exists(strLocalDbLocation))
{
File.Delete(strLocalDbLocation);
}
SqlCeEngine sceEngine = new SqlCeEngine(#"Data Source= " + strLocalDbLocation + ";Persist Security Info=True;Password=MyPass");
sceEngine.CreateDatabase();
}
catch
{ }
}
public static void UpdateLocalDatabase(String strTableName, DataTable dttTable)
{
try
{
// Opening the Connection
sceConnection = CreateDatabaseSQLCEConnection();
sceConnection.Open();
// Creating tables in sdf file - checking headers and types and adding them to a query
StringBuilder stbSqlGetHeaders = new StringBuilder();
stbSqlGetHeaders.Append("create table " + strTableName + " (");
int z = 0;
foreach (DataColumn col in dttTable.Columns)
{
if (z != 0) stbSqlGetHeaders.Append(", "); ;
String strName = col.ColumnName;
String strType = col.DataType.ToString();
if (strType.Equals("")) throw new ArgumentException("DataType Empty");
if (strType.Equals("System.Int32")) strType = "int";
if (strType.Equals("System.String")) strType = "nvarchar (100)";
if (strType.Equals("System.Boolean")) strType = "nvarchar (15)";
if (strType.Equals("System.DateTime")) strType = "datetime";
if (strType.Equals("System.Byte[]")) strType = "nvarchar (100)";
stbSqlGetHeaders.Append(strName + " " + strType);
z++;
}
stbSqlGetHeaders.Append(" )");
SqlCeCommand sceCreateTableCommand;
string strCreateTableQuery = stbSqlGetHeaders.ToString();
sceCreateTableCommand = new SqlCeCommand(strCreateTableQuery, sceConnection);
sceCreateTableCommand.ExecuteNonQuery();
StringBuilder stbSqlQuery = new StringBuilder();
StringBuilder stbFields = new StringBuilder();
StringBuilder stbParameters = new StringBuilder();
stbSqlQuery.Append("insert into " + strTableName + " (");
foreach (DataColumn col in dttTable.Columns)
{
stbFields.Append(col.ColumnName);
stbParameters.Append("#" + col.ColumnName.ToLower());
if (col.ColumnName != dttTable.Columns[dttTable.Columns.Count - 1].ColumnName)
{
stbFields.Append(", ");
stbParameters.Append(", ");
}
}
stbSqlQuery.Append(stbFields.ToString() + ") ");
stbSqlQuery.Append("values (");
stbSqlQuery.Append(stbParameters.ToString() + ") ");
string strTotalRows = dttTable.Rows.Count.ToString();
foreach (DataRow row in dttTable.Rows)
{
SqlCeCommand sceInsertCommand = new SqlCeCommand(stbSqlQuery.ToString(), sceConnection);
foreach (DataColumn col in dttTable.Columns)
{
if (col.ColumnName.ToLower() == "ssma_timestamp")
{
sceInsertCommand.Parameters.AddWithValue("#" + col.ColumnName.ToLower(), "");
}
else
{
sceInsertCommand.Parameters.AddWithValue("#" + col.ColumnName.ToLower(), row[col.ColumnName]);
}
}
sceInsertCommand.ExecuteNonQuery();
}
}
catch { }
}
I have been over my code numerous times and hope someone can help me see something I don't. I'm trying to pull data from Excel into a SQL table with multiple columns in VS2010 but when I try uploading the data, I get the error "Cannot Find Column 8." I see nothing wrong with column 8 nor any of the other columns. Anyone else? Thanks!
protected void Button1_Click(object sender, EventArgs e)
{
//make local copy
string sheetname = "Sheet1";
string path = Server.MapPath("~/Import.xls");
//connect to local Excel
try
{
FileUpload.SaveAs(path);
System.Data.OleDb.OleDbConnection MyConnection;
System.Data.DataSet DtSet;
System.Data.OleDb.OleDbDataAdapter MyCommand; //check sheet name
MyConnection = new System.Data.OleDb.OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + path + ";Extended Properties=Excel 12.0;");
MyCommand = new System.Data.OleDb.OleDbDataAdapter("select * from [" + sheetname + "$]", MyConnection);
MyCommand.TableMappings.Add("Table", "TestTable");
DtSet = new System.Data.DataSet();
MyCommand.Fill(DtSet);
SqlConnection curConnection = new SqlConnection(#"Data Source=1tc-Techcomm2;Initial Catalog=EventManagement;Integrated Security=True");
curConnection.Open();
SqlCommand curCommand;
SqlParameter param;
string str;
for (int i = 0; i < DtSet.Tables[0].Rows.Count; i++)
{
if (DtSet.Tables[0].Rows[i][1] == DBNull.Value)
continue;
curCommand = curConnection.CreateCommand();
curCommand.CommandText = #"Insert into TestSP (SessionHead_Title, SessionHead_Type, SessionHead_Description, SessionHead_Confirmed, SessionHead_Presenter, SessionHead_Champion, SessionHead_Objective, SessionHead_Notes, SessionHead_Schedule, SessionHead_Equipment, SessionHead_Hardware, SessionHead_CDA) Values (#a,#b,#c,#d,#e,#f,#g,#h,#i,#j,#k,#l,#m)";
for (int j = 0; j < 13; j++)
{
param = new SqlParameter();
str = "#";
str += (char)('a' + j);
param.ParameterName = str;
param.SqlDbType = SqlDbType.VarChar;
param.Value = DtSet.Tables[0].Rows[i][j];//This is where it errors out at after 8 times through
curCommand.Parameters.Add(param);
}
Label1.Text = "THE EXCEL DATE HAS SUCCESSFULLY BEEN SENT TO THE DATABASE";
int Event_Id = curCommand.ExecuteNonQuery();
}
MyConnection.Close();
curConnection.Close();
}
catch (Exception ex)
{
//Response.Write(ex.ToString());
Label1.Text = ex.Message;
}
}
I believe the issue was that the spreadsheet column headers did not match the table headers. I read somewhere that the Column names in SQL Server table must be the same in the Excel file. I guess this solves it...thanks for the help!
If you know the structure of your Table on the SQL Server, Try using the SqlBulkCopy. Map your columns and write it to the server. You already have the data in your DataSet.
SqlBulkCopy _bc = new SqlBulkCopy(curConnection);
_bc.DestinationTableName = "TestSP";
_bc.ColumnMappings.Add(new SqlBulkCopyColumnMapping("DataTableColumnName1", "SQLServerColumnName1");
_bc.ColumnMappings.Add(new SqlBulkCopyColumnMapping("DataTableColumnName2", "SQLServerColumnName2");
_bc.ColumnMappings.Add(new SqlBulkCopyColumnMapping("DataTableColumnName3", "SQLServerColumnName3");
_bc.ColumnMappings.Add(new SqlBulkCopyColumnMapping("DataTableColumnName4", "SQLServerColumnName4");
_bc.WriteToServer(DtSet.Tables[0]);
You can still use this process if you don't know the structure but you will have to get creative. I had to do that and it was pretty fun.
The solution of user3611272 helped me:
... i tried to append some random table and went to "Advanced Options" at the bottom of the append pop up in this u will see some "Stored Column mappings" and some mappings in it, now delete all of them the relevant mapping and hit "Accept" now u can append the table