使用 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
的表,其中包含 TempTestTableId
、Age
和 Name
列。我写了这个(基于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
只会查看DataRow
的RowState
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 数据适配器更新和插入行不会更新(仅插入)的主要内容,如果未能解决你的问题,请参考以下文章
/var/lib/postgresql/data 尽管有明确的插入和更新行,但 docker 中时间刻度的盲挂载文件夹数据不会更新
Sql Server 2005 - 插入更新触发器 - 获取更新,插入行