使用SqlDataAdapter.Update可以方便地对数据库进行快速、批量数据更新。我们最常用的多条数据更新方法是使用循环多次执行SQL语句或存储过程,这样虽然方便,但由于连接和数据传递要在服务器和客户端多次来往,大大增加了整个过程的时间,当数据越大时越明显!
使用SqlDataAdapter.Update更新有三种方式,即SqlCommandBuiler自动生成更新,使用配置数据源方式更新,手动编写命令
SqlCommandBuiler方式:
public static void AddInfo() { string str1 = "Server=.;user=sa;pwd=sa;database=One_db"; SqlConnection conn = new SqlConnection(str1); conn.Open(); SqlCommand cmd = new SqlCommand("select * from Info", conn); DataTable dt = new DataTable(); SqlDataAdapter da = new SqlDataAdapter(cmd); da.Fill(dt); for (int i = 0; i < 4; i++) { dt.Rows.Add(new object[] { i + 4, "aa0" + i, "soft", "12345678945" }); } SqlCommandBuilder scb = new SqlCommandBuilder(da); da.Update(dt.GetChanges()); dt.AcceptChanges(); outValueDT(dt);////显示datatable信息 conn.Close(); }
软件运行之前 数据库的数据为:
运行之后的数据为:
2、执行删除和修改命令
public static void DeleteInfo() { string str1 = "Server=.;user=sa;pwd=sa;database=One_db"; SqlConnection conn = new SqlConnection(str1); conn.Open(); SqlCommand cmd = new SqlCommand("select * from Info", conn); DataTable dt = new DataTable(); SqlDataAdapter da = new SqlDataAdapter(cmd); da.Fill(dt); dt.Rows[0][1] = "wangyu"; dt.Rows[1][3] = "13924658789";
dt.Rows.RemoveAt(2); //dt.Rows[3].Delete(); SqlCommandBuilder scb = new SqlCommandBuilder(da); da.Update(dt.GetChanges()); dt.AcceptChanges(); outValueDT(dt); //显示datatable信息 conn.Close(); }
如果没有设置主键 将会出现错误
执行后将出错,错误信息“对于不返回任何键列信息的 SelectCommand,不支持 UpdateCommand 的动态 SQL 生成。”
出错原因是建表时没有设置主键。主键唯一标识一行数据,SqlCommandBuilder是根据DataTable每行的RowState及对应的主键来生成命令的,没有主键就无法确定删除哪条数据,当然不可能根据其他列来删除,因为其他列可能重复,这样会删除多行数据,很可能执行后不是你想要的结果,这种不确定性的对数据的操作方法,微软当然不可能提供给你!
使用dt.Rows.RemoveAt(2) 显示dt时, 发现 dt里面的索引值为2的行被删除,但是 数据库里面的相应行并没有被删除
想要删除数据库里面的 需要使用dt.Rows[2].Delete();
修改代码后 第0行第一列的数据 第1行第3列的数据 已经修改 ,索引值为2的row删除 数据库数据为:
注意:
使用RemoveAt或Remove会将数据真正的从DataTable中删除,而使用Delete则不会,而仅是把当前行的RowState值置为deleted.
前面说过SqlCommandBuilder是根据RowState和主键来生成命令的,RemoveAt/Remove把数据删除了,怎么能找到主键和RowState呢?
所以使用SqlCommandBuilder时应该注意的2点:表要有主键,应使用delete方法删除行.SqlCommandBuilder用来自动生成添加、删除、修改的语句
在使用Update()这个函数前,我们得知道一点,那就是一个DataTable有个记录RowState的字段(不知称其为字段合适不合适),当我们对表进行过添加、修改、删除之后,这个RowState会记录我们的操作,而Update()方法正是根据RowState进行对数据库表的更新的。但有点需要注意,那就是添加和删除操作:当我们使用Add()方法添加一个新行和Delete()方法删除一行的时候是没有问题的,DataTable都正确记录下来了我们的操作,并能在Update()函数下正确更新到数据库中,但是当我们使用Import()方法导入一行或Remove()删除一行的时候,我们此时再使用Update()方法,发现我们的添加和删除没有成功,这是为什么呢?我们分别来看一下:
Import()方法,我们导入的是一个已经存在于其他表里的行,而这个被导入的行的RowState记录的是什么是不确定的,所以导入到我们的DataTable中的时候,我们的DataTable并不一定把这一行当作是添加的行;
RemoveAt()方法,在我们使用RemoveAt()方法的时候,我们的DataTable并没有真正的把这一行删除了,而只是记录了一个删除状态,当我们使用DataTable的AcceptChanges()的时候,记录为删除状态的行才被真正删除了,而RemoveAt()方法是直接把行删除了,所以再使用Update()方法时没有实现对数据库对应表的行删除功能。
当我们完成了Update()函数之后应该调用DataTable()的AcceptChanges()方法,把DataTable的RowState记录初始化。用进行过RowState初始化(即调用过AcceptChanges ())的DataTable去Update()数据库中的表,将不会进行任何更新。
我在项目里用这个Update()方法的时候是这么用的:我并不是从数据库中先读出一张DataTable,进行一些添加或删除或修改,然后Update(),而是我有一张现成的dataTable,我最初的想法是想让我的这张DataTable和数据库中对应的表进行对比,然后根据两张表的不同之处进行更新,但实际上这是无法实现的,是我最初没有真正明白Update()函数的原理。所以,SqlDataAdapter的Update()方法不是拿数据库中的表和程序中的一个DataTable进行对比更新,而是根据程序中的DataTable中记录的RowState进行更新。
所以,我们想要使用这个Update()方法实现批量更新,必须让我们的DataTable正确记录所有的RowState,当更新完成后还应调用AcceptChanges()方法对DataTable的RowState进行初始化。