Using an SQL Data Adapter to update and insert rows doesn't update (only inserts)

StackOverflow https://stackoverflow.com/questions/21239060

  •  30-09-2022
  •  | 
  •  

Вопрос

I am just playing around with this at the moment, ultimately I want to read a CSV file into memory and then insert the records into an SQL database. Existing records should be updated, records that are missing should be added. Records that don't exist in the new CSV shouldn't be deleted, however.

I've been playing around the example from the MSDN library. I understand that the SqlDataAdapter can perform bulk updates quite quickly.

I created a little mock app with a table called TempTestTable that has TempTestTableId, Age, and Name columns. I wrote this (based on the MSDN Article):

using (SqlConnection connection =
   new SqlConnection("data source=localhost;initial catalog=fishsticks;integrated security=True;MultipleActiveResultSets=True;"))
{
    SqlDataAdapter dataAdpater = new SqlDataAdapter(
      "SELECT temptesttableid, Age, Name FROM TempTestTable",
      connection);

    dataAdpater.UpdateCommand = new SqlCommand(
       "UPDATE TempTestTable SET Age = @Age, Name = @Name " +
       "WHERE TempTestTableId = @TempTestTableId", connection);

    dataAdpater.InsertCommand = new SqlCommand(
       "INSERT INTO TempTestTable (Age, Name) " +
       "VALUES (@Age, @Name)", connection);

    SqlParameter parameter = dataAdpater.UpdateCommand.Parameters.Add(
       "@TempTestTableId", SqlDbType.Int);

    dataAdpater.InsertCommand.Parameters.Add(
      "@Age", SqlDbType.Int, 10, "Age");

    dataAdpater.InsertCommand.Parameters.Add(
      "@Name", SqlDbType.NVarChar, 50, "Name");

    dataAdpater.UpdateCommand.Parameters.Add(
      "@Age", SqlDbType.Int, 10, "Age");

    dataAdpater.UpdateCommand.Parameters.Add(
      "@Name", SqlDbType.NVarChar, 50, "Name");

    parameter.SourceColumn = "TempTestTableId";
    parameter.SourceVersion = DataRowVersion.Original;

    DataTable tempTestTable = new DataTable();

    tempTestTable.Columns.Add("Age");
    tempTestTable.Columns.Add("Name");
    tempTestTable.Columns.Add("TempTestTableId");

    var row1 = tempTestTable.NewRow();

    row1["Age"] = 10;
    row1["Name"] = "Smith";
    row1["TempTestTableId"] = 1;

    var row2 = tempTestTable.NewRow();

    row2["Age"] = 40;
    row2["Name"] = "Jones";
    row2["TempTestTableId"] = 2;

    tempTestTable.Rows.Add(row1);
    tempTestTable.Rows.Add(row2);

    dataAdpater.Update(tempTestTable);

There is already a record in the database with TempTestTableId = 1, so the idea was that in theory it would update that record, as well as insert a new record with ID 2. However, when I run the code, it inserts both items.

Any ideas?

Это было полезно?

Решение

No, the DataAdapter will just look at the DataRow's RowState property. If it's Added the InsertCommand will be executed, if it's Modified the UpdateCommand will be executed. You have to load this row into the table from the database first.

You can fill an empty DataTable with a DataAdapter and your SelectCommand including two parameters. If the table is empty you can add the DataRow manually, otherwise you can modify the rows with the updated values (if any) and call dataAdpater.Update(tempTestTable).

Here's an example (untested):

SqlDataAdapter dataAdpater = new SqlDataAdapter(
  "SELECT temptesttableid, Age, Name FROM TempTestTable WHERE Name = @Name",
  connection);

DataTable testTable = new DataTable();
// note that you should use an available csv-parser instead
foreach (string line in File.ReadAllLines(path))
{ 
    string[] columns = line.Split(new char[]{'\t'}, StringSplitOptions.None);
    if(columns.Length >= 2)
    {
        string name = columns[0].Trim();
        string ageStr = columns[1].Trim();
        int age;
        if (int.TryParse(ageStr, out age))
        {
            dataAdpater.SelectCommand.Parameters.AddWithValue("@Name", name);
            int rowsAdded = dataAdpater.Fill(testTable);
            if (rowsAdded == 0)
            {
                testTable.Rows.Add(name, age);
            }
            else
            {
                // update values?
            }
        }
    }
}
dataAdpater.Update(testTable);
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top