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
事件只会在实际更新行时发生
所以。。。三个具体问题:
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=
,我将接受它。