C# SqlCommandBuilder是如何工作的,如何停止ReSharper';她建议删除它吗?

C# SqlCommandBuilder是如何工作的,如何停止ReSharper';她建议删除它吗?,c#,resharper,dataadapter,sqldataadapter,sqlcommandbuilder,C#,Resharper,Dataadapter,Sqldataadapter,Sqlcommandbuilder,我不明白它是怎么回事。我有以下代码: public void TestCommandBuilder() { var pubsDataSet = new DataSet("Pubs"); var pubs = ConfigurationManager.ConnectionStrings["PubsConnectionString"]; var connection = new SqlConnection(pubs.ConnectionString); SqlComm

我不明白它是怎么回事。我有以下代码:

public void TestCommandBuilder()
{
    var pubsDataSet = new DataSet("Pubs");
    var pubs = ConfigurationManager.ConnectionStrings["PubsConnectionString"];
    var connection = new SqlConnection(pubs.ConnectionString);
    SqlCommand cmd = connection.CreateCommand();
    cmd.CommandType = CommandType.Text;
    cmd.CommandText = "SELECT * FROM Publishers";
    var da = new SqlDataAdapter(cmd);

    da.Fill(pubsDataSet, "publishers");
    foreach (DataRow row in pubsDataSet.Tables["publishers"].Rows)
    {
        row["pub_name"] = "Updated " + DateTime.Now.Minute + DateTime.Now.Second;
    }

    // The variable builder is not used
    var builder = new SqlCommandBuilder(da);

    da.UpdateBatchSize = 3;
    da.RowUpdated += DaRowUpdated;

    da.Update(pubsDataSet, "publishers");
}

private void DaRowUpdated(object sender, SqlRowUpdatedEventArgs e)
{
    Console.WriteLine("Rows: " + e.RecordsAffected + "\r\n");
}
变量
builder
没有在任何地方使用,我也没有调用
GetUpdateCommand()
方法,就像它们在上所做的那样。我只创建了
SqlCommandBuilder
,并将
SqlDataAdapter
传递给它。但代码运行良好

如果你看代码,它看起来像一行

var builder = new SqlCommandBuilder(da);
可以安全地删除。事实上,ReSharper建议删除它。但是如果我这样做了,代码将不再运行,因为
SqlDataAdapter
不知道如何执行更新

在调试模式下,我注意到在执行该行之后,
SqlDataAdapter
UpdateCommand
属性仍然是
null
。从-docs中,我得到
SqlCommandBuilder
将自己注册到
SqlDataAdapter
RowUpdated
事件中

但当该事件被触发时,它会做什么?
SqlDataBuilder
是否实际执行更新本身

我还注意到,如果我删除
SqlCommandBuilder
,我的
DaRowUpdated
方法会触发一次,就在
da.Update
语句发生InvalidOperationException之前。我没有料到。我认为
RowUpdated
事件只会在实际更新行时发生

所以。。。三个具体问题:

  • 如何防止ReSharper建议删除此行
  • 编写像
    SqlCommandBuilder
    这样的类,其中代码没有以任何方式表明创建实例正在使用传入的
    SqlDataAdapter
    执行某些操作,这种做法是否不好
  • 这是一辆汽车吗

  • 如果不使用该变量,则绝对没有必要使用它。如果构造函数中发生了有用的事情,您仍然可以调用:

    var builder = new SqlCommandBuilder(da);
    
    应该是:

    new SqlCommandBuilder(da);
    

    这应该在不改变代码行为的情况下处理警告。这看起来有点奇怪,如果这真的是必要的,我对
    SqlCommandBuilder
    的设计有点怀疑。但在实践中,这样的用法基本上与普通方法调用相同。

    我的理解是,在构造command builder对象的过程中,它在DataAdapter上添加了对自身的引用,因此它知道如何构建CRUD命令

    请注意上面链接备注下的这一部分

    *

    SqlDataAdapter不会自动生成Transact-SQL 将对数据集所做的更改与 SQL Server的关联实例。但是,您可以创建一个 用于自动生成Transact-SQL的SqlCommandBuilder对象 如果设置SelectCommand,则用于单表更新的语句 SqlDataAdapter的属性。然后,任何附加的Transact-SQL 未设置的语句由SqlCommandBuilder生成


    *根据我对这个问题的评论:

        public void TestCommandBuilder()
        {
            var pubs = ConfigurationManager.ConnectionStrings["PubsConnectionString"];
    
            using (var pubsDataSet = new DataSet("Pubs"))
            using (var connection = new SqlConnection(pubs.ConnectionString))
            using (SqlCommand cmd = connection.CreateCommand())
            {
                cmd.CommandType = CommandType.Text;
                cmd.CommandText = "SELECT * FROM Publishers";
    
                using (var da = new SqlDataAdapter(cmd))
                using (new SqlCommandBuilder(da))
                {
                    da.UpdateBatchSize = 3;
                    da.RowUpdated += DaRowUpdated;
                    da.Fill(pubsDataSet, "publishers");
                    foreach (DataRow row in pubsDataSet.Tables["publishers"].Rows)
                    {
                        row["pub_name"] = "Updated " + DateTime.Now.Minute + DateTime.Now.Second;
                    }
    
                    da.Update(pubsDataSet, "publishers");
                }
            }
        }
    
        private void DaRowUpdated(object sender, SqlRowUpdatedEventArgs e)
        {
            Console.WriteLine("Rows: " + e.RecordsAffected);
        }
    

    卸载重竖琴?这对我来说太神奇了。您有许多对象实现了
    IDisposable
    。使用块将它们包装在
    中,以确保资源得到确定的释放。我会在下面弹出一个关于它应该是什么样子的答案。也许我还是应该保留一个参考资料,这样我最终就能处理掉它。@comecme,好主意。由于它确实实现了
    IDisposable
    ,您应该使用
    块将其包装在
    中。使用
    语句将其包装在
    中不会使警告消失,因为
    builder
    仍然不会在其他任何地方使用。但是,我可以通过使用(新的SqlCommandBuilder(da))
    编写
    ,将您的答案与使用
    结合起来。我不知道在
    中使用
    是可能的,但它确实是。对于resharper,你只能接受它,因为你不能在粒度级别上排除类似的项目。但是,我同意应该在using语句中使用它。我认为您可能必须在更新行之前移动构建,因为您正在连接到事件DataRowUpdate。是不是
    da.Update(pubsDataSet,“发布者”)执行更新,这是在事件挂接后发生的?正确后执行对数据库的更新。但是,我认为事件(RowUpdate)的接线需要在数据更改之前完成。如果查看链接中的MSDN示例,您将看到它在数据适配器初始化后立即连接。您可以在调用
    da.Update()
    之前立即创建
    SqlCommandBuilder
    ,而不会出现问题。但是,您的代码仍然在
    builder
    上向我发出重新竖琴警告。但它似乎可以通过使用
    和(newsqlcommandbuilder(da))da.Update(pubsDataSet,“publisher”)。我假设这仍然会调用
    Dispose
    ,但我不确定。我可以测试一下吗?@JesseC.Slicer:我已经尝试过使用ILSpy,但我不知道应该查找什么来检查是否调用了Dispose。然而,我刚刚创建了自己的类,实现了
    IDisposable
    ,并向其中添加了析构函数。即使我不使用变量,我也会看到在执行析构函数之前调用
    Dispose
    。因此,是的,
    using
    语句仍然调用
    Dispose
    ,如果您没有将实例分配给变量。如果您从答案中删除
    var builder=
    ,我将接受它。