3

我不明白它是怎么SqlCommandBuilder做的。我有以下代码:

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不在任何地方使用,我也不像在MSDNGetUpdateCommand()上那样调用该方法。我只创建,将其传递给. 但代码工作正常。SqlCommandBuilderSqlDataAdapter

如果你看一下代码,它似乎是一行

var builder = new SqlCommandBuilder(da);

可以安全删除。事实上,ReSharper 建议删除它。但如果我这样做了,代码将不再运行,因为SqlDataAdapter它不知道如何执行更新。

在调试模式下,我注意到在执行该行之后,SqlDataAdapter'UpdateCommand属性仍然是null. 从MSDN文档中,我了解到将SqlCommandBuilder自身注册RowUpdatedSqlDataAdapter.

但是当那个事件被触发时它会做什么呢?实际上是在SqlDataBuilder执行更新本身吗?

我注意到的其他事情,如果我删除SqlCommandBuilder,我的DaRowUpdated方法被触发一次,就在da.Update语句上发生 InvalidOperationException 之前。我没想到的是。我认为该RowUpdated事件仅在实际更新行时发生。

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

  1. 如何防止 ReSharper 建议删除此行?
  2. 编写一个像这样的类是不好的做法SqlCommandBuilder,其中代码没有以任何方式表明创建一个实例正在对SqlDataAdapter传入的东西做某事?
  3. 这是一种设计模式吗?
4

3 回答 3

3

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

var builder = new SqlCommandBuilder(da);

应该:

new SqlCommandBuilder(da);

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

于 2012-06-24T19:25:07.743 回答
1

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

    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);
    }
于 2012-06-25T02:02:53.690 回答
0

我的理解是在构建命令构建器对象期间,它在 DataAdapter 上添加了对自身的引用,因此它知道如何构建 CRUD 命令。

请注意您在上面发布的链接的备注下的此部分。

*

SqlDataAdapter 不会自动生成对 DataSet 所做的更改与 SQL Server 的关联实例进行协调所需的 Transact-SQL 语句。但是,如果您设置 SqlDataAdapter 的 SelectCommand 属性,您可以创建一个 SqlCommandBuilder 对象来自动生成单表更新的 Transact-SQL 语句。然后,您未设置的任何其他 Transact-SQL 语句都由 SqlCommandBuilder 生成。

*

于 2012-06-25T01:19:48.113 回答