none
如何修改DataAdapter.UpdateCommand.CommandText? RRS feed

  • 问题


  • 以下是一个测试生成DataRow更新数据库纪录的测试(数据库中已存在一条主键Col2为2的纪录,目的是更新该记录其余两列)。

    SqlDataAdapter adapter = new SqlDataAdapter("SELECT * FROM Table1", conn);
                SqlCommandBuilder cmdbuilder = new SqlCommandBuilder(adapter);
                adapter.UpdateCommand = cmdbuilder.GetUpdateCommand();
                adapter.DeleteCommand = cmdbuilder.GetDeleteCommand();
                adapter.InsertCommand = cmdbuilder.GetInsertCommand();
    
                DataTable table = new DataTable();
    
                adapter.FillSchema(table, SchemaType.Mapped);
    
                DataRow row = table.NewRow();
                
                row["Col2"] = 2;
                row["Col1"] = "sdfaagwe";
                row["Col3"] = "sfawetqwg";
                
                table.Rows.Add(row);
                row.AcceptChanges();
    
                row["Col3"] = "test";
                row["Col1"] = "yedaoq";
    
                adapter.UpdateCommand.CommandText = "UPDATE [Table1] SET [Col1] = @p1, [Col2] = @p2, [Col3] = @p3 WHERE  ([Col2] = @p6)";
    
                int count = adapter.Update(table);


    这里有一个问题:

    自动生成的UpdateCommand不仅要求主键匹配,其它列也要求匹配。eg:

    UPDATE [Table1] SET [Col1] = @p1, [Col2] = @p2, [Col3] = @p3 WHERE (((@p4 = 1 AND [Col1] IS NULL) OR ([Col1] = @p5)) AND ([Col2] = @p6) AND ((@p7 = 1 AND [Col3] IS NULL) OR ([Col3] = @p8)))
    

    这导致我不得不先赋一些初值再AcceptChanges以形成Original:
    row["Col1"
    
    ] = "sdfaagwe"
    
    ;
                row["Col3"
    
    ] = "sfawetqwg"
    
    ;
                
                table.Rows.Add(row);
                row.AcceptChanges();
    

    为了避免这样的情况,我在程序中尝试修改自动生成的UpdateCommand,使其仅根据主键进行匹配。

    问题就出在这里,根据调试过程发现,UpdateCommand.CommandText的设置代码执行成功;但是,在调用Adapter.Update后,UpdateCommand.CommandText被重置为:

    UPDATE [Table1] SET [Col1] = @p1, [Col3] = @p2 WHERE (((@p3 = 1 AND [Col1] IS NULL) OR ([Col1] = @p4)) AND ([Col2] = @p5) AND ((@p6 = 1 AND [Col3] IS NULL) OR ([Col3] = @p7)))
    

    我很纳闷为什么会这样?
    2010年3月16日 8:21

答案

  • adapter自动生成代码的时候有个选项的,问update/delete是否包含状态还是互斥之类的,是的话就会生成一大堆条件出来,否的话就只有主键进行匹配了。

    另外,要改adapter的语句的话最好是直接在class.designer.cs里面改,就不会有问题了,程序中改的话也许会自动重设为之前定义的内容。

    vs的版本不同行为也有所不同,反正有设计器的控件尽量在设计器中改
    霸王
    • 已标记为答案 泉子 2010年3月16日 8:47
    2010年3月16日 8:36
  • 你好!

    这是正常的,原因是为了在并发发的情况下保证数据更新的有效性。比如只用主键进行更新时,若出现多个人同时获取并更新同一条记录,那么数据库中只会记录最后一个人更新后的信息,这时就出现问题了因为这个结果并不是其它人需要的。SqlDataAdapter 默认会使用 “开放式并发” 即把所有列的原始值都带入到条件中,这样出现并发时只有第一提交信息的人会成功,之后的人都会失败,从而保证了数据的完整性。

    另外,建议你使用强类型数据集,VS 会为你自动生成大部分代码,如果你不需要使用“开发式并发” 你也可以在 TableAdapter 中高级选中取消“使用开放式并发”。

    建立强类型数据集的方式:

    1 在你的项目中添加一个数据集文件(*.xsd)
    2 打开新建的文件,在左边的“服务资源管理器中”建立一个数据库连接,并将你需要的表拖进来。



    知识改变命运,奋斗成就人生!
    • 已标记为答案 泉子 2010年3月16日 9:07
    2010年3月16日 8:57
    版主
  • 我不清楚你的项目具体是怎样的,但从你问题的描述内容看,你使用代码的方式创建 DataAdapter 来更新数据,其实这里就可以使用类型化的数据集这样你只需要写少量的代码就能实现功能,因大部分内容都是生成的同时也会避免一些常见问题,相比之下更可靠工作效率更高。
    知识改变命运,奋斗成就人生!
    • 已标记为答案 泉子 2010年3月17日 1:08
    2010年3月16日 9:16
    版主
  • 看看这个地址:http://msdn.microsoft.com/zh-cn/library/6sb6kb28(VS.80).aspx

    会写固然是重要的,合理利用工具把简单繁琐的事最好交给工具去做,让自己有时间去做去学习更多有意义的事。

    知识改变命运,奋斗成就人生!
    • 已标记为答案 泉子 2010年3月17日 1:08
    2010年3月16日 10:00
    版主

全部回复

  • adapter自动生成代码的时候有个选项的,问update/delete是否包含状态还是互斥之类的,是的话就会生成一大堆条件出来,否的话就只有主键进行匹配了。

    另外,要改adapter的语句的话最好是直接在class.designer.cs里面改,就不会有问题了,程序中改的话也许会自动重设为之前定义的内容。

    vs的版本不同行为也有所不同,反正有设计器的控件尽量在设计器中改
    霸王
    • 已标记为答案 泉子 2010年3月16日 8:47
    2010年3月16日 8:36
  • Thanks.
    DbCommandBuilder. ConflictOption 属性设置为OverwriteChanges可使生成的Update和Delete语句仅包含主键。
    2010年3月16日 8:47
  • 你好!

    这是正常的,原因是为了在并发发的情况下保证数据更新的有效性。比如只用主键进行更新时,若出现多个人同时获取并更新同一条记录,那么数据库中只会记录最后一个人更新后的信息,这时就出现问题了因为这个结果并不是其它人需要的。SqlDataAdapter 默认会使用 “开放式并发” 即把所有列的原始值都带入到条件中,这样出现并发时只有第一提交信息的人会成功,之后的人都会失败,从而保证了数据的完整性。

    另外,建议你使用强类型数据集,VS 会为你自动生成大部分代码,如果你不需要使用“开发式并发” 你也可以在 TableAdapter 中高级选中取消“使用开放式并发”。

    建立强类型数据集的方式:

    1 在你的项目中添加一个数据集文件(*.xsd)
    2 打开新建的文件,在左边的“服务资源管理器中”建立一个数据库连接,并将你需要的表拖进来。



    知识改变命运,奋斗成就人生!
    • 已标记为答案 泉子 2010年3月16日 9:07
    2010年3月16日 8:57
    版主
  • 谢谢LS,不过我想我的项目并不适合所谓强类型数据库。一则我们需要支持多种数据库,二则我不希望把数据一直保存在DataSet中。
    2010年3月16日 9:07
  • 我不清楚你的项目具体是怎样的,但从你问题的描述内容看,你使用代码的方式创建 DataAdapter 来更新数据,其实这里就可以使用类型化的数据集这样你只需要写少量的代码就能实现功能,因大部分内容都是生成的同时也会避免一些常见问题,相比之下更可靠工作效率更高。
    知识改变命运,奋斗成就人生!
    • 已标记为答案 泉子 2010年3月17日 1:08
    2010年3月16日 9:16
    版主
  • 我没太用过设计器之类的支持来生成数据库存取代码嘞,从学生时代起一直就只知道写代码,呵呵。看来是我对你说的类型化数据集不够了解。
    如果有什么资料或示例的话,麻烦给我介绍一下哈。
    2010年3月16日 9:50
  • 看看这个地址:http://msdn.microsoft.com/zh-cn/library/6sb6kb28(VS.80).aspx

    会写固然是重要的,合理利用工具把简单繁琐的事最好交给工具去做,让自己有时间去做去学习更多有意义的事。

    知识改变命运,奋斗成就人生!
    • 已标记为答案 泉子 2010年3月17日 1:08
    2010年3月16日 10:00
    版主
  • 哈,谢了,我这两天去熟悉熟悉。
    2010年3月17日 1:08
  • adapter自动生成代码的时候有个选项的,问update/delete是否包含状态还是互斥之类的,,这个怎么设置
    2010年9月3日 16:41
  • 不清楚你说的是什么,不知道是不是DbCommandBuilder .ConflictOption 
    2010年9月13日 7:16