C#: Deleting row in DataTable does not apply to data bank - c#

My task should be quite simple but after hours and hours I must admit I'm completely stuck!
I simply want to delete a datarow from a datatable. My datatable is a copy of the table in my current dataset in a SQLite databank. It is mandatory to use the table.row.Delete() method. I am aware that delete() just marks the row to be deleted upon table update.
Below is the code I'm currently using:
I retrieve my data via:
public DataTable GetTable(string tableName)
{
string connectionPath = dbVariables.ConnectionString;
try
{
SQLiteConnection myConnection = new SQLiteConnection(connectionPath);
myConnection.Open();
string cmdStr = "SELECT * FROM " + tableName;
DataTable myTable = new DataTable();
SQLiteDataAdapter myAdapter = new SQLiteDataAdapter(cmdStr, myConnection);
myAdapter.FillSchema(myTable, SchemaType.Source);
myTable.Columns[dbVariables.ClassesID].AutoIncrement = true;
myTable.Columns[dbVariables.ClassesID].AutoIncrementSeed = 1;
myTable.Columns[dbVariables.ClassesID].AutoIncrementStep = 1;
myAdapter.Fill(myTable);
myConnection.Close();
return myTable;
}
catch (SQLiteException e)
{
MessageBox.Show(e.ToString());
return null;
}
}
Here I manipulate my data:
if (myResult == DialogResult.Yes)
{
//killTable.AcceptChanges();
DataRow[] dr = killTable.Select("" + cmVariables.ClassName + " = '" + cmbClasses.Text + "'");
//First I need to evaluate the row index of the row I want to delete
string indexName = (killTable.Rows.IndexOf(dr[0])).ToString();
int i = Int32.Parse(indexName);
// And we are done - I got my row index
DataRow modifiedRow = killTable.Rows[i];
killTable.Rows[i].Delete();
//I inserted this messagebox just to see the rowstatus - and yes, it is marked as deleted on runtime...
MessageBox.Show(killTable.Rows[i].RowState);
// I refer to this in the text below
killTable.AcceptChanges();
killClass_Execution(killTable, cmbClasses.Text, ShortClassNm);
}
And at least the code to update my datatable back to the databank:
public void UpdateTable(string tableName, DataTable sourceTable, bool newOrEdit)
{
try
{
string connectionPath = dbVariables.ConnectionString;
//Connection erstellen --> der connectString gibt dabei den Pfad an.
SQLiteConnection myConnection = new SQLiteConnection(connectionPath);
myConnection.Open();
//Einen Befehls-String erstellen, der das UPDATE-Command auslöst
// UPDATE cm_ClassTest SET className = userEditInput WHERE className = 'oldClassName'
string myUpdateString = "SELECT * FROM " + tableName + "";
SQLiteDataAdapter myAdapter = new SQLiteDataAdapter(myUpdateString, myConnection);
SQLiteCommandBuilder comBuild = new SQLiteCommandBuilder(myAdapter);
myAdapter.DeleteCommand = comBuild.GetDeleteCommand(true);
myAdapter.UpdateCommand = comBuild.GetUpdateCommand(true);
myAdapter.InsertCommand = comBuild.GetInsertCommand(true);
myAdapter.Update(sourceTable);
myConnection.Close();
if (newOrEdit == true)
{
MessageBox.Show("Klasse erstellt!");
}
else
{
MessageBox.Show("Klasse aktualisiert!");
}
}
catch (SQLiteException e)
{
MessageBox.Show(e.ToString());
}
}
In the code block for manipulating data you will find the AcceptChanges() method. At this time, there may have been no other changes appeared to my datatable - so after app start, deleting a row may be the users first action.
Also: each entry in my dataset is unique (school classes that are labeled with a unique class name).
Any help will be highly appreciated!
Regards,
Aran

OK - so I succeeded (finally). Debugging showed no issues, except for AcceptChanges() which got a call but did not result in actually deleting the dataRow.
All I can think of right now is that my primary approach to it was part of the problem: I get my DataTable right from the DataBase, do all the manipulations with it, and then send it back to DB via Update (see my update method above). The SQLite CommandBuilder seems not capable of interpreting my DAtaRow which is by then flagged 'Deleted', but kind of rubber-stamps it to the end of the method without throwing an exception.
By doing so I tried the GetChanges-Method:
DataRow[] dr = killTable.Select("" + cmVariables.ClassName + " = '" + cmbClasses.Text + "'");
string indexName = (killTable.Rows.IndexOf(dr[0])).ToString();
int i = Int32.Parse(indexName);
killTable.Rows[i].Delete();
DataTable killItTable = killTable.GetChanges(DataRowState.Deleted);
killClass_Execution(killItTable, cmbClasses.Text, ShortClassNm);
Now it's working - the copy of killTable (killItTable - stupid I know, but first thing I do tomorrow morning is give it better names :) ) provides info for the sql commandbuilder which seems to be recognized by it.
Whatever it is - it now works.
I think this is not supposed to happen - if someone can come up with any good suggestions, on how to improve my approach, I shall be glad.
best regards

Related

C# Windows Form using OracleDataAdapter to insert rows to a Oracle Table from a System DataTable

I'm writing a windows form that populates a DataTable and I want it to insert into an Oracle Table. I've seen some examples here that use the OracleDataAdapter to do this so I don't have to loop through all the records. The code doesn't have any errors but when I check the Table using Toad(I did refresh) I don't see it. I used the example below
Update and insert records into Oracle table using OracleDataAdapter from DataTable
Here is how my DataTable is made:
public DataTable dtMain = new DataTable();
public void FillTable(DataTable dt)
{
dtMain.Columns.Add("SERIAL", typeof(System.String));
dtMain.Columns.Add("LOCATION", typeof(System.String));
dtMain.Columns.Add("UPC", typeof(System.String));
dtMain.Columns.Add("PRODUCT", typeof(System.String));
dtMain.Columns.Add("CREATED_BY", typeof(System.String));
dtMain.Columns.Add("CREATED_DATE", typeof(System.DateTime));
dtMain.Columns.Add("SKU", typeof(System.String));
dtMain.Columns.Add("MAN_DATE", typeof(System.DateTime));
dtUpload.Columns[0].Unique = true;
dtMain.Merge(dt);
}
This is the how I'm trying to insert into the database
private void btnUpload_Click(object sender, EventArgs e)
{
DataTable dt = new DataTable();
string strSelect = "SELECT serial, upc, man_date, location, product, created_by, created_date, serial from schema.table where rownum < 2";
string strInsert = "INSERT INTO schema.table (serial, upc, man_date, location, product, created_by, created_date, serial) VALUES (:serial, :upc, :man_date, :location, :product, :created_by, :created_date, :serial)";
string conStr = ConfigurationManager.ConnectionStrings["connection"].ConnectionString;
OracleConnection connection = new OracleConnection(conStr);
connection.Open();
if (connection.State != ConnectionState.Open)
{
return;
}
try
{
OracleDataAdapter adapterS = new OracleDataAdapter();
adapterS.SelectCommand = new OracleCommand(strSelect, connection);
adapterS.Fill(dt);
dt.Rows.Remove(dt.Rows[0]);
dt.Merge(dtUpload);
}
catch (Exception ex)
{
string x = ex.Message + ex.StackTrace;
throw;
}
for (int i = 0; dt.Rows.Count > i; i++)
{
OracleDataAdapter adapter = new OracleDataAdapter();
adapter.InsertCommand = new OracleCommand(strInsert, connection);
adapter.InsertCommand.BindByName = true;
OracleParameter pSerial = new OracleParameter(":serial", OracleDbType.Varchar2);
pSerial.SourceColumn = dt.Columns[0].ColumnName;
pSerial.Value = dtUpload.Rows[i][0];
OracleParameter pLocation = new OracleParameter(":location", OracleDbType.Varchar2);
pLocation.SourceColumn = dt.Columns[1].ColumnName;
pLocation.Value = dtUpload.Rows[i][1];
OracleParameter pUPC = new OracleParameter(":upc", OracleDbType.Date);
pUPC.SourceColumn = dt.Columns[2].ColumnName;
pUPC.Value = dtUpload.Rows[i][2];
OracleParameter pProduct = new OracleParameter(":product", OracleDbType.Varchar2);
pProduct.SourceColumn = dt.Columns[3].ColumnName;
pProduct.Value = dtUpload.Rows[i][3];
OracleParameter pCreatedBy = new OracleParameter(":created_by", OracleDbType.Varchar2);
pCreatedBy.SourceColumn = dt.Columns[4].ColumnName;
pCreatedBy.Value = dtUpload.Rows[i][4];
OracleParameter pCreatedDate = new OracleParameter(":created_date", OracleDbType.Varchar2);
pCreatedDate.SourceColumn = dt.Columns[5].ColumnName;
pCreatedDate.Value = dtUpload.Rows[i][5];
OracleParameter pSKU = new OracleParameter(":SKU", OracleDbType.Date);
pSKU.SourceColumn = dt.Columns[6].ColumnName;
pSKU.Value = dtUpload.Rows[i][6];
OracleParameter pManDate = new OracleParameter(":man_date", OracleDbType.Varchar2);
pManDate.SourceColumn = dt.Columns[7].ColumnName;
pManDate.Value = dtUpload.Rows[i][7];
adapter.InsertCommand.Parameters.Add(pSerial);
adapter.InsertCommand.Parameters.Add(pLocation);
adapter.InsertCommand.Parameters.Add(pUPC);
adapter.InsertCommand.Parameters.Add(pProduct);
adapter.InsertCommand.Parameters.Add(pCreatedBy);
adapter.InsertCommand.Parameters.Add(pCreatedDate);
adapter.InsertCommand.Parameters.Add(pserial);
adapter.InsertCommand.Parameters.Add(pManDate);
}
try
{
adapter.Update(dt);
}
catch (Exception ex)
{
string x = ex.Message + ex.StackTrace;
throw;
}
connection.Close();
connection.Dispose();
}
If someone can give me some pointers that would be great, I've been Googling for 2 days and I just can't figure it out. I bet it's something simple
Update:
Thank you for the reply, it took me a bit to get back to this project. When I posted this I didn't realize I forgot to include my select statement.
For the OracleParameter value, I thought using SourceColumn would use that column for the values.
I did update the DataTable with the serial being unique. It still doesn't insert the data. If I included the Parameter.value would I have loop row by row to do this? Above I corrected/updated it with the current code.
Second Update:
Ok, I tried looping through the parameters to add the values from the DataTable, no errors but still not inserting in the database. I know my connectionstring is correct because the select query works. The code above has been updated for the changes I made. If some Oracle guru can shed some light on my problem a virtual high-five is waiting for them.
I never used OracleDataAdapter but I see these possible issues:
I don't think you can use OracleDataAdapter straight away, first you have to select an existing table from Oracle and based on this result you can do Update/Insert/Delete on it. Where is your strSelect string? I don't see it.
You created all the OracleParameter but I don't see that you assign any value to it, they are all empty. I would expect something like pOptoroLP.Value = ...; before you make any insert.
You should define a unique, resp. Primary Key column like dt.Columns["SERIAL"].Unique = true; in order to make Update() or Delete(). Maybe it is not required for Insert(), I don't know.
Did you follow the examples in Data Provider for .NET Developer's Guide
I finally found the problem, the row state in the DataTable needs to in the state of Added for it to work. If someone else has this problem here is my new code and you can compare it to what I was trying to do. Thank you Wernfried Domscheit for the Oracle part but it turned out to be my DataTable was the issue though setting the Unique column was probably an issue as well, I didn't check. The OracleCommandBuilder took care of the insert statements and parameters for me.
private void btnUpload_Click(object sender, EventArgs e)
{
DataTable dt = new DataTable();
string strSelect = "SELECT serial, upc, man_date, location, product, created_by, created_date, serial from schema.table where rownum < 2";
string strInsert = "INSERT INTO schema.table (serial, upc, man_date, location, product, created_by, created_date, serial) VALUES (:serial, :upc, :man_date, :location, :product, :created_by, :created_date, :serial)";
string conStr = ConfigurationManager.ConnectionStrings["connection"].ConnectionString;
OracleConnection connection = new OracleConnection(conStr);
connection.Open();
if (connection.State != ConnectionState.Open)
{
return;
}
OracleDataAdapter adapter = new OracleDataAdapter(strSelect, conStr);
OracleCommandBuilder builder = new OracleCommandBuilder(adapter);
adapter.Fill(dt);
dt.Columns["SERIAL"].Unique = true;
dt.Merge(dtUpload);
dt.Rows.Remove(dt.Rows[0]);
foreach (DataRow row in dt.Rows)
{
row.SetAdded();
}
try
{
adapter.Update(dt);
}
catch (Exception ex)
{
string x = ex.Message + ex.StackTrace;
throw;
}
finally
{
connection.Close();
connection.Dispose();
}
}

Unidata UniObjects for .NET - Write amendments back to unidata from modified table

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.

Why is my returned DataSet instance has no tables?

When I connect to the DB and I want to read data from table it doesn't work an shows these
Exception Details:
System.IndexOutOfRangeException: Cannot find table 0.
Error in Line 141
I have only one table in the dataset. Do you know the best way to read from table for me ? I return only one table. When I use foreach, how can I read a one row data?
internal DataSet read(string query)
{
DataSet nds = new DataSet();
try
{
string connectionString = "...";
try
{
SqlConnection nsqlc = new SqlConnection(connectionString);
SqlCommand get = new SqlCommand(query, nsqlc);
nsqlc.Open();
SqlDataAdapter nsda = new SqlDataAdapter(get);
nsda.Fill(nds);
nsqlc.Close();
}
catch (Exception)
{
}
return nds;
}
catch (Exception)
{
return nds;
}
}
Main form :
links = links + t.Tables[0].Rows[i][0].ToString() + "%";
String links = "";
links = "movie%";
DataSet t = n.read("select id , poster from Movie order by id desc");
for (int i = 0; i < 10; i++)
{
links = links + t.Tables[0].Rows[i][0].ToString() + "%";
links = links + t.Tables[0].Rows[i][1] + "%";
}
The closest thing to an answer here would have to be that the n.read method returns a DataSet instance that has no tables in it. You need to step into the method with a debugger and figure out why it behaves like that.
If you see what the problem is, fix it. If not, share the read method code and someone will be able to help you further.
Looking at your updated post, I see that you are swallowing every possible exceptions that could occur while trying to fetch data. Remove the catch block from your read method. This will allow you to see what the real problem is.
Exception swallowing is something you'll want to take away from your code on a global scale. I'd suggest that you do some Googling to find out why it's a terrible habit.
About a "better way to read from table", you should consider using a IDataReader.
string links = "movie%";
using (var connection = new SqlConnection("your connection string");
{
using (var command = someExistingConnection.CreateCommand())
{
command.CommandText = "select id, poster from Movie order by id desc";
command.Connection = connection;
connection.Open();
try
{
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
var idValue = reader.GetObject(0).ToString(); // would be better to use actual field type, which is unknown at the time I'm writing this
var posterValue = reader.GetString(1);
// perform concatenation here using the two variables declared above
links += String.Format("{0}%{1}%", idValue, posterValue);
}
}
}
finally
{
connection.Close();
}
}
}
This will outperform working with a DataSet by a long shot.

Pulling a SELECT query into a datatable and accessing it

I'm writing a small ASP.net C# web page and it keeps giving me an error stating:
There is no row at position 0.
I'm probably doing it wrong but here is some of my code:
string SqlQuery = "SELECT * ";
SqlQuery += " FROM main_list";
SqlQuery += " WHERE ID = #FindID";
SqlConnection conn = new SqlConnection("server=???;database=contacts;User
ID=???;Password=???;");
conn.Open();
SqlCommand SqlCmd = new SqlCommand(SqlQuery, conn);
SqlCmd.Parameters.Add("#FindID",searchID);
SqlDataAdapter da = new SqlDataAdapter(SqlCmd);
try {
da.Fill(dt);
fillData(p);
}
catch {
txtId.Text = "ERROR";
}
And FillData is the following:
protected void fillData(int pos) {
txtId.Text = dt.Rows[pos]["ID"].ToString();
txtCompany.Text = dt.Rows[pos]["Company"].ToString();
txtFirstName.Text = dt.Rows[pos]["First_Name"].ToString();
txtLastName.Text = dt.Rows[pos]["Last_Name"].ToString();
txtAddress1.Text = dt.Rows[pos]["Address1"].ToString();
txtAddress2.Text = dt.Rows[pos]["Address2"].ToString();
txtCity.Text = dt.Rows[pos]["City"].ToString();
txtState.Text = dt.Rows[pos]["State"].ToString();
txtZipCode.Text = dt.Rows[pos]["ZipCode"].ToString();
txtPhoneNum1.Text = dt.Rows[pos]["Phone_Num"].ToString();
txtPhoneNum2.Text = dt.Rows[pos]["Phone_Num2"].ToString();
txtFax.Text = dt.Rows[pos]["Fax_Num"].ToString();
txtEmail.Text = dt.Rows[pos]["Email"].ToString();
txtNotes.Text = dt.Rows[pos]["Notes"].ToString();
txtCategory.Text = dt.Rows[pos]["Category"].ToString();
txtSubCategory.Text = dt.Rows[pos]["SubCategory"].ToString();
txtDateAdded.Text = dt.Rows[pos]["DateAdded"].ToString();
txtDateModified.Text = dt.Rows[0]["DateModified"].ToString();
}
Here is the call that errors out:
protected void btnPrev_Click(object sender, EventArgs e) {
p--;
lblPage.Text = p.ToString();
fillData(p-1);
}
protected void btnNext_Click(object sender, EventArgs e) {
p++;
lblPage.Text = p.ToString();
fillData(p-1);
}
I'm trying to cycle thru the Rows[0] to Rows[1] or however many there is but it gives me the error about no row at position 0 or position 1. It only fills once and then errors out.
EDIT:
I'm trying to access the second row returned by the database after already accessing one row already. For example: Rows[0] is accessible fine but then when I try to read Rows[1] it errors and says it doesn't have a row in position 1. I can revise the code to return Rows[1] and it works but when I try to access Rows[0] it breaks. This is why I pass the variable (p) to fillData so it can show only that Rows value. Thanks!
EDIT 2: I believe it's because there is a postback that wipes the values retrieved by the database. Is there a way to get the database entries to stay even after a postback? If not I am guessing I will have to query the database every time.
The error message indicates there are no rows being returned by SQL. Are you sure there is data to be returned.
When you use dt.Rows[0] you are effectively saying "take the first row that comes back, and get a value from it." If the DataTable doesn't have any rows (i.e. your SQL query returns no matches), that's like saying "Here is a plate that contains no apples. Take the first apple and tell me what colour it is" - see? Doesn't make sense.
What you should do is check whether there are any rows before you try to read them...
if(dt.Rows.Count > 0)
{
// do stuff here.
}
Use Linq and a stored procedure it is much nicer
datacontext context = new datacontext();
var result = context.MyStoredProc(searchID).FirstOrDefault();
Try changing
SqlCmd.Parameters.Add("#FindID",searchID);
to
SqlCmd.Parameters.AddWithValue("#FindID",searchID);
Check your query on your database, make sure rows are actually being returned. Also, it's bad practice to put your query directly into your code like that, especially when using parameters. You might want to try something like this:
private Int32 CallStoredProcedure(Int32 FindId)
{
using (var dt = new DataTable())
{
using (var conn = new SqlConnection(ConnectionString))
{
using (var sqlCmd = new SqlCommand("SEL_StoredProcedure", conn))
{
using (var sda = new SqlDataAdapter(sqlCmd))
{
sqlCmd.CommandType = System.Data.CommandType.StoredProcedure;
sqlCmd.Parameters.AddWithValue("#FindId", FindId);
sqlCmd.Connection.Open();
sda.Fill(dt);
}
}
}
if (dt.Rows.Count == 1)
return Convert.ToInt32(dt.Rows[0]["ID"]);
else if (dt.Rows.Count > 1)
throw new Exception("Multiple records were found with supplied ID; ID = " + studentId.ToString());
}
return 0;
}
To set up your stored procedure, on your database run this:
CREATE procedure [dbo].[SEL_StoredProcedure]
#FindId int = null
as
SELECT * FROM main_list where ID = #FindId
Just remove the index identifier from the code:
e.g.
txtId.Text = dt.Rows["ID"].ToString();

Export SQL DataBase to WinForm DataSet and then to MDB Database using DataSet

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 { }
}

Categories