ADO.NET Best Practices for Connection and DataAdaptor Object Scope

风格不统一 提交于 2021-02-08 13:34:11

问题


This is my first post on StackOverflow, so please be gentle...

I have some questions regarding object scope for ADO.NET.

When I connect to a database, I typically use code like this:

OleDbConnection conn = new OleDbConnection("my_connection_string");
conn.Open();
OleDbDataAdapter adapter = new OleDbDataAdapter("SELECT * from Employees", conn);
OleDbCommandBuilder cb = new OleDbCommandBuilder(adapter);
DataTable dt = new DataTable();
adapter.Fill(dt);
conn.Close();
conn.Dispose();

Let's say that I bind the resulting DataTable to a grid control and allow my users to edit the grid contents. Now, when my users press a Save button, I need to call this code:

adapter.Update(dt);

Here are my questions:

1) Do I need to retain the adapter object that I created when I originally loaded the datatable, or can I create another adapter object in the Save button click event to perform the update?

2) If I do need to retain the original adapter object, do I also need to keep the connection object available and open?

I understand the disconnected model of ADO.NET - I'm just confused on object scope when it's time to update the database. If someone could give me a few pointers on best practices for this scenario, I would greatly appreciate it!

Thanks in advance...


回答1:


1) You don't need the same DataAdapter, but if you create a new one it must use the same query as its base.

2) The DataAdapter will open its connection if the connection is closed. In that case it will close the connection again after it is done. If the connection is already open it will leave the connection open even after it is done.

Normally you would work as in your example. Create a Conneciton and a DataAdapter, fill a DataTable and dispose of the Connection and the DataAdapter afterwards.

Two comments to your code:

  • You don't need the CommandBuilder here since you only do a select. The command builder is only needed if you want to generate Insert, Update or Delete statements automatically. In that case you also need to set the InsertCommand, UpdateCommand or DeleteCommand on the DataAdapter manually from the CommandBuilder.
  • Second. Instead of calling Dispose manually you should use the Using clause. It ensures that your objects will be disposed of even if an exception is thrown.

Try to change your code to this:

DataTable dt = new DataTable();
using (OleDbConnection conn = new OleDbConnection("my_connection_string"))
using (OleDbDataAdapter adapter = new OleDbDataAdapter("SELECT * from Employees", conn))
{
  adapter.Fill(dt);    
}

Note that I define the DataTable outside the using clauses. This is needed to ensure that the table is in scope when you leave the usings. Also note that you don't need the Dispose call on the DataAdapter or the Close call on the Connection. Both are done implicitly when you leave the usings.

Oh. And welcome to SO :-)




回答2:


To answer your questions:

  1. Ideally, you should retain the same DataAdapter because it has already performed it's initialization. A DataAdapter provides properties such as the SelectCommand, UpdateCommand, InsertCommand and DeleteCommand which allow you to set different Command objects to perform these different function on the datasource. So, you see, the DataAdapter is designed to be reused for multiple commands (for the same database connection). Your use of the CommandBuilder (though, not recommended) creates the other Commands by analysing the SelectCommand, thus allowing you to perform Updates, Deletes and Inserts using the same CommandBuilder.

  2. It is best to allow the DataAdapter to implicitly handle database connections. @Rune Grimstad has already elaborated on this implicit behaviour and it's useful to understand this. Ideally, connections should be closed as soon as possible.




回答3:


There are two additional details worth adding to Rune Grimstad's excellent answer.

First, the CommandBuilder (if it is needed) implements IDisposable, and therefore should be wrapped in its own 'using' statement. Surprisingly (at least to me), Disposing the DataAdapter does not appear to Dispose the associated CommandBuilder. The problem I observed when I failed to do this was that even though I called Dispose on the DataAdapter, and the Connection state was 'Closed', I could not remove a temporary database once I had used a CommandBuilder to Update that database.

Second, the statement "... In that case you also need to set the InsertCommand, UpdateCommand or DeleteCommand on the DataAdapter manually ..." is not always correct. For many trivial cases, the CommandBuilder will automatically create the correct INSERT, UPDATE, and DELETE statements based on the SELECT statement provided to the DataAdapter, and meta data from the database. 'Trivial', in this case, means that only a single table is accessed and that table has a Primary Key that is returned as part of the SELECT statement.



来源:https://stackoverflow.com/questions/594053/ado-net-best-practices-for-connection-and-dataadaptor-object-scope

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!