我如何知道哪些行是新添加的,哪些不是?
你不需要;DGV 显示的数据表已经在跟踪这一点。如果您制作 SqlDataAdapter 并将SqlCommandBuilder 插入其中, 请参阅文档中的示例代码,以便它在其 InsertCommand/UpdateCommand/DeleteCommand 属性中获得查询(或者您可以将这些命令放入自己,但考虑到这一点并没有多大意义命令生成器可以自动生成它们)然后您只需说:
theDataAdapter.Update(theDataTable);
如果您没有将其保存在其他任何地方,您可以从 DGV 的 DataSource 中获取它:
theDataAdapter.Update(dgView.DataSource as DataTable);
顺便说一句,这里的“更新”一词与更新查询无关;Microsoft 应该将其称为 SaveChanges。它运行各种修改查询 (I/U/D) 而不仅仅是 UPDATE
如果你真的想知道,并且有重新发明这个轮子的强烈愿望,你可以检查 DataRow 的 RowState 属性,它会告诉你它是添加、修改还是删除,所以你可以触发适当的查询(但真的是你d 重新实现 SqlDataAdapter 已经内置的功能)
综上所述,您可能没有意识到您可以通过以下方式大大简化您的生活:
- 将新的 DataSet 类型的文件添加到您的项目中(就像您添加一个类一样)。打开它
- 右键单击它的表面,选择添加 TableAdapter
- (一次)设计您的连接字符串
- 将您的查询输入为“产生行的选择”,例如
SELECT * FROM SomeTable WHERE ID = Id
(建议使用在 ID 上选择的 where 子句;您可以稍后添加更多查询以执行其他操作,例如,SELECT * FROM SomeTable WHERE SomeColumn LIKE @someValue
但现在选择 ID 为您提供了一个基本查询使用方便加载相关数据)。如果需要,您还可以使用现有的或新的存储过程
- 给它一个合理的名称对,例如 FillById、GetDataById - FillBy 填充现有表,Get 获取新表
- 结束
现在,您的代码中将有可用的对象,这些对象是包装器数据适配器和数据表 - 功能相同,但强类型更好
例如,您可以使用以下内容填充您的网格:
var ta = new SomeTableAdapter();
dgView.DataSource = ta.GetDataByFirstName("John%"); //does select * from table where firstname like 'john%' into a datatable
数据表是强类型的,所以你不能像这样访问它们:
//no
foreach(DataRow row in someTable.Rows){
if((row["someColumn"] as string) == "hello" && row.IsNull("otherColumn"))
row["otherColumn"] = "goodbye";
}
您已命名属性:
//yes
foreach(var row in someTable){
if((row.SomeColumn == "hello" && row.IsOtherColumnNull())
row.OtherColumn = "goodbye";
}
好多了。LINQ 也适用于它们,无需 AsEnumerable 或 Cast 并且无休止地转换值。
这不是魔术。VS 在幕后为您编写大量代码 - 检查 YourDataSet.Designer.cs 文件 - 数百个完全参数化的 SqlCommand,用于所有表操作(选择/插入/更新/删除),所有基础都无需键入 SELECT 命令进入工具窗格。即使这么多年过去了,它真的很好用。
哦,但是设计器在网络核心中工作得不是很好。他们在修复 netcore 带来的错误方面确实落后(其他优先事项)