使用 SQL 数据适配器更新和插入行不会更新(仅插入)

Posted

技术标签:

【中文标题】使用 SQL 数据适配器更新和插入行不会更新(仅插入)【英文标题】:Using an SQL Data Adapter to update and insert rows doesn't update (only inserts) 【发布时间】:2014-01-20 16:22:07 【问题描述】:

我现在只是在玩这个,最终我想将 CSV 文件读入内存,然后将记录插入 SQL 数据库。应更新现有记录,应添加缺失的记录。但是,不应删除新 CSV 中不存在的记录。

我一直在玩 MSDN 库中的示例。我知道 SqlDataAdapter 可以非常快速地执行批量更新。

我创建了一个小模拟应用程序,其中包含一个名为 TempTestTable 的表,其中包含 TempTestTableIdAgeName 列。我写了这个(基于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);

数据库中已经有一条记录为TempTestTableId = 1,所以理论上它会更新该记录,并插入一条 ID 为 2 的新记录。但是,当我运行代码时,它会插入两个项目。

有什么想法吗?

【问题讨论】:

不,DataAdapter 只会查看DataRowRowState property。如果是Added,则将执行InsertCommand,如果是Modified,则将执行UpdateCommand。您必须先将此行从数据库加载到表中。 最初我从 MSDN 中提取的示例是这样做的,但我需要从 CSV 加载,所以我如何从数据库和 CSV 中读取?我是否必须将当前数据库表读入数据表,然后循环遍历它并根据我的 CSV 手动检查每一行,更改值或插入新行,并设置 RowState,然后提交? 你可以用DataAdapter和你的SelectCommand填充一个空的DataTable,包括两个参数。如果表为空,您可以手动添加DataRow,否则您可以使用更新的值(如果有)修改行并调用dataAdpater.Update(tempTestTable) 嗯,这听起来很混乱,你有例子吗?无论如何,我都会试一试 想我已经明白了,我将我的数据库表加载到 DataTable 中,执行所有操作(添加、更新等)然后调用 .Update()。这似乎做到了,希望它会很快。 【参考方案1】:

不,DataAdapter 只会查看 DataRow 的 RowState 属性。如果是Added,则将执行InsertCommand,如果是Modified,则将执行UpdateCommand。您必须先将此行从数据库中加载到表中。

您可以用DataAdapter 和您的SelectCommand 填充一个空的DataTable,包括两个参数。如果表为空,您可以手动添加DataRow,否则您可以使用更新的值(如果有)修改行并调用dataAdpater.Update(tempTestTable)

这是一个示例(未经测试):

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);

【讨论】:

谢谢,将着手实施。我想在更新值部分我必须定义一个 UpdateCommand 并以某种方式执行它。实际上,如果没有定义 AddCommand,我不确定 AddWithValue 将如何工作......

以上是关于使用 SQL 数据适配器更新和插入行不会更新(仅插入)的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server 2008 行插入和更新时间戳

/var/lib/postgresql/data 尽管有明确的插入和更新行,但 docker 中时间刻度的盲挂载文件夹数据不会更新

更新或插入 SQL Server 时忽略错误行

Sql Server 2005 - 插入更新触发器 - 获取更新,插入行

使用 SQL Server DTS 包有条件地在目标表中插入/更新行

SQL插入和更新不会更新或插入所有记录,只有少数记录