SqlDataAdapter.Update批量数据更新

使用SqlDataAdapter.Update可以方便地对数据库进行快速、批量数据更新。我们最常用的多条数据更新方法是使用循环多次执行SQL语句或存储过程,这样虽然方便,但由于连接和数据传递要在服务器和客户端多次来往,大大增加了整个过程的时间,当数据越大时越明显!

使用SqlDataAdapter.Update更新有三种方式,即SqlCommandBuiler自动生成更新,使用配置数据源方式更新,手动编写命令

SqlCommandBuiler方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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、执行删除和修改命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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";<br>       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进行初始化。

 

posted @   笑笑小白  阅读(1881)  评论(0编辑  收藏  举报
编辑推荐:
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示