Search code examples
c#resharperdataadaptersqldataadaptersqlcommandbuilder

How does SqlCommandBuilder do its stuff and how can I stop ReSharper's suggestion to delete it?


I don't understand how SqlCommandBuilder does its thing. I have the following code:

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");
}

The variable builder is not used anywhere and I do not call the GetUpdateCommand() method, like they do on MSDN. I only create the SqlCommandBuilder, passing it a SqlDataAdapter. But the code just works fine.

If you look at the code, it seems like the line

var builder = new SqlCommandBuilder(da);

can be safely deleted. In fact, ReSharper is suggesting to remove it. But if I do, the code doesn't run anymore, as the SqlDataAdapter doesn't know how to perform an update.

In debug mode I noticed that after executing that line, the SqlDataAdapter's UpdateCommand property is still null. From the MSDN-docs I get that the SqlCommandBuilder registers itself to the RowUpdated event of the SqlDataAdapter.

But what does it do when that event is triggered? Is the SqlDataBuilder actually performing the update itself?

Something else I noticed, if I remove the SqlCommandBuilder, my DaRowUpdated method is triggered once, just before the InvalidOperationException occurs on the da.Update statement. I did not expect that. I'd think the RowUpdated event only occurs when a row has actually been updated.

So... three concrete questions:

  1. How can I prevent ReSharper from suggesting to delete this line?
  2. Is it bad practice to program a class like SqlCommandBuilder, where the code doesn't indicate in any way that creating an instance is doing something with the SqlDataAdapter passed in?
  3. Is this a design pattern?

Solution

  • As per my comment on the question:

        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);
        }