4

I select * from an Excel spreadsheet into DataTable dt. I want to take those values and update the SQL table. The SQL table exists because of a manual import to SQL from the original Excel spreadsheet, has a primary key set. The user updates the excel sheet and I need to update the SQL values. I am setting the dt.RowState to modified in an effort to invoke the update. I get no error but the SQL table does not update. Previous test show my SQL permissions and connection is good, I can modify the table.

connectionToSQL = new SqlConnection(SQLConnString);
connectionToSQL.Open();
var cmd = new SqlCommand("SELECT * FROM TAGS$",connectionToSQL);                 
var da = new SqlDataAdapter(cmd);
var b = new SqlCommandBuilder(da);
foreach (DataRow r in dt.Rows)
{
    r.SetModified();
}
da.Update(dt);   
Toni
  • 1,555
  • 4
  • 15
  • 23
cjjeeper
  • 93
  • 3
  • 4
  • 13
  • There's nothing in the provided code which actually modifies any DataRow objects, nor gives us an idea of any example column names in the database that you expect to be able to modify. Please add in an example of modifying a column's value inside the foreach loop, and test again for yourself that you're still not seeing an UPDATE statement executed, and we can delve deeper. – Alex Norcliffe Nov 17 '11 at 17:39
  • Where is this dt coming from? Try assigning your datatable, as your foreach is not looping through anything? – IAmGroot Nov 17 '11 at 17:48
  • Have you considered using [SQL profiler](http://msdn.microsoft.com/en-us/library/ms181091.aspx) to see if any SQL is actually going to the SQL server? – Conrad Frix Nov 17 '11 at 17:51
  • the dt is coming from "I select * from an Excel spreadsheet into dt." – cjjeeper Nov 17 '11 at 22:11
  • I am not modifying the values in dt. please re-read the question. The values in the dt from excel are different than the values in the SQL table. The foreach Loop sets the rowstate to "modified" manually in order to invoke the UPDATE. – cjjeeper Nov 17 '11 at 22:12
  • Alex please take another look at the whole question. The issue is really getting the datatable to look like it has been modified so it executes an update on all the rows. – cjjeeper Nov 17 '11 at 22:16
  • I may be dense, but you're not actually doing anything to the database; only the Excel file. Also the variable DT does not exist in the scope of the code snipet. Please, post the entire code. It just looks like you're trying to modify the Excel, not the SQL Database –  Nov 18 '11 at 00:09
  • Check your rows' HasVersion and see if you actually have an original and modified version on them. If not, your update won't work. If all of the data actually exists in the table (so you're ONLY modifying rows, not inserting them), you might be able to fake the necessary condition by using the AcceptChanges method. So, r.SetModified(), then r.AcceptChanges(), then r.SetModified again. – B H Sep 04 '15 at 15:37

3 Answers3

10

Try this:

using System.Data;
using System.Data.SqlClient;
using System;
namespace Q308507 {
    class Class1 
    {
        static void Main(string[] args) 
        {
            SqlConnection cn = new SqlConnection();
            DataSet CustomersDataSet = new DataSet();
            SqlDataAdapter da;
            SqlCommandBuilder cmdBuilder;
            // Set the connection string of the SqlConnection object
            // to connect to the SQL Server database in which you
            // created the sample table.
            cn.ConnectionString =
            "Server=server;Database=northwind;UID=login;PWD=password;";
            cn.Open();      
            // Initialize the SqlDataAdapter object by specifying a
            // Select command that retrieves data from the sample table.
            da = new SqlDataAdapter("select * from CustTest order by CustId", cn);
            // Initialize the SqlCommandBuilder object to automatically
            // generate and initialize the UpdateCommand,
            // InsertCommand, and DeleteCommand properties
            // of the SqlDataAdapter.
            cmdBuilder = new SqlCommandBuilder(da);
            // Populate the DataSet by running the Fill method
            // of the SqlDataAdapter.
            da.Fill(CustomersDataSet, "Customers");
            // Display the Update, Insert, and Delete commands
            // that were automatically generated
            // by the SqlCommandBuilder object.
            Console.WriteLine(
                "Update command Generated by the Command Builder : ");
            Console.WriteLine(
                "==================================================");
            Console.WriteLine(
                cmdBuilder.GetUpdateCommand().CommandText);
            Console.WriteLine("         ");
            Console.WriteLine(
                "Insert command Generated by the Command Builder : ");
            Console.WriteLine(
                "==================================================");
            Console.WriteLine(cmdBuilder.GetInsertCommand().CommandText);
            Console.WriteLine("         ");        
            Console.WriteLine(
                "Delete command Generated by the Command Builder : ");
            Console.WriteLine(
                "==================================================");
            Console.WriteLine(cmdBuilder.GetDeleteCommand().CommandText);
            Console.WriteLine("         ");
            // Write out the value in the CustName field before
            // updating the data using the DataSet.
            Console.WriteLine("Customer Name before Update : " +
                CustomersDataSet.Tables["Customers"].Rows[0]["CustName"]);
    
            // Modify the value of the CustName field.
            CustomersDataSet.Tables["Customers"].Rows[0]["CustName"] = "Jack";
            // Post the data modification to the database.
            da.Update(CustomersDataSet, "Customers");        
            Console.WriteLine("Customer Name updated successfully");
            // Close the database connection.
            cn.Close();
            // Pause
            Console.ReadLine();
        }
    }
}
Toni
  • 1,555
  • 4
  • 15
  • 23
Keith Costa
  • 1,783
  • 11
  • 35
  • 68
  • This doesn't really apply. I will not be modifying the values in my datatable. They are different than the SQL table because of user input to the source Excel sheet. – cjjeeper Nov 17 '11 at 22:14
  • The issue is really getting the datatable to look like it has been modified so it executes an update on all the rows. – cjjeeper Nov 17 '11 at 22:15
2

I think the auto generated SqlCommands generated by SqlCommandBuilder are not really going to be suitable in your case (If I have understood the question correctly). In the WHERE clause of the SQL Update statements generated by SqlCommandBuilder,the values of ALL columns are compared with their original values (as determined by the original data values in the DataRow). If the original values are not matched in the destination database, no rows will get updated.

This link to the SqlCommandBuilder may help :

http://msdn.microsoft.com/en-us/library/ms971491.aspx

From that link, try to understand : "adCriteriaAllCols" as that is what SqlCommandBuilder uses. I suspect what you want is "AdCriteriaKey" behaviour.

One possible solution might be to NOT use SqlCommandBuilder, and simply write the INSERT/UPDATE/DELETE SqlCommands yourself, and attach them to SqlDataAdapter.InsertCommand, UpdateCommand,and DeleteCommand.
There's some example code at : http://support.microsoft.com/kb/308055

EDIT : the SqlCommandBuilder in .net versions 2.0 and later have a ConflictOption property. The default used is : CompareAllSearchableValues. Try using : OverwriteChanges, which will cause the WHERE clause generated in SQL statements to only compare the primary key values.

Moe Sisko
  • 11,665
  • 8
  • 50
  • 80
  • Yes, I was headed in this direction. I am currently looking for some old code where I "thought" I had already done what I am trying to do with excel and a database. It must have been the OleDbAdapter though and I am wondering if there is a difference. Alex suggested writing over my datable Selected from SQL with the data from Excel which may be the (slightly) more efficient method. – cjjeeper Nov 22 '11 at 23:02
  • BTW, you are 100% correct. I had reviewed the update command in the text visualizer and it wasn't going to update anything. But again - I am plagued with remembering doing this previously somehow---so I think anyway. If I find it and get it to work I will post the code. – cjjeeper Nov 22 '11 at 23:04
  • actually, it might be possible to get the commandbuilder to update based just on the primary key. Try : sqlCommandBuilder.ConflictOption = ConflictOption.OverwriteChanges – Moe Sisko Nov 22 '11 at 23:30
1

I tried commenting but was told to re-read the question. So I did, and it didn't help :) You have very little code in that example which ties dt (you say this is populated from Excel) to the database. You have the variables connectionToSQL, cmd, da and b. These are connected to a database. You then iterate through dt, which isn't. This is why in my comment I asked for the example sourcecode where you're modifying rows in dt - because I presumed you would have that somewhere, in order to expect that the changes would jump from Excel (which populated dt) to your database.

I see that you're calling da.Update(dt); Try opening a new dataset from the database, and going through the rows in dt, applying the changes to the rows in your new dataset. From what I can tell - and there's not much code there - no commands are issued because the dataadapter knows the internal rows of dt did not come from its datasource. That's my stab, anyway.

Alex Norcliffe
  • 2,439
  • 2
  • 17
  • 21
  • Thank you Alex. I think I see your thought process here. Let me try to add some more information. The changes in excel happen inside excel by the end user. They save the changes and close the workbook and give it to me. I then run my program and select * from the Excelworkbook into dt. At this point dt is a datatable with some values in it. It is unmodified. The Values in dt are different than the SQL table that is an import from the original Excel. – cjjeeper Nov 18 '11 at 05:22
  • So I have a dt in memory that is just an unmodified datatable but I want to send it to SQL because 'I' know the data is (or maybe) different. So I iterate through it to set the rowstate to modified to invoke the Update command to work on the table. That is the only work I am doing on the table. So my issue is the update command is not doing anything even though I have set all the rows to "Modified". (I could paste all the ImportExcel code here but it is a lot and doesn't do anything except Fill a dt with everything in a sheet. – cjjeeper Nov 18 '11 at 05:29
  • Thanks for the clarification - I already got that though, but my point is you're changing the backing store of all of those rows implicitly. Just marking the rows as modified, and then issuing an Update for the entire dataset to a DataAdapter that uses another source would not (AFAIK) issue the updates. Hence my suggestion (in part as a diagnosis operation, too) is to create a separate dataset from the destination datasource, and copy the values over in your loop before issuing the update. – Alex Norcliffe Nov 18 '11 at 16:18
  • Ah, I see what you are saying now. Yes, that should work in theory. – cjjeeper Nov 22 '11 at 22:59
  • ******Instead of setting the row to "modified" I set the row to "added" (using a loop) and then da.update works as expected.****** – cjjeeper Oct 30 '13 at 17:00