简体   繁体   English

如何从SqlConnection对象中“分离”SqlDataReader?

[英]How can I “detach” a SqlDataReader from its SqlConnection object?

I have a method ("GetDataReader," let's call it) that returns a SqlDataReader. 我有一个方法(“GetDataReader,”让我们称之为)返回一个SqlDataReader。 It's inside a Singleton DataFactory class that maintains a persistent connection to the database. 它位于Singleton DataFactory类中,用于维护与数据库的持久连接。

The problem with this is that after being returned, the DataReader is still "connected" to the Connection object in my DataFactory. 这样做的问题是,在返回之后,DataReader仍然“连接”到我的DataFactory中的Connection对象。 So, I have to make sure the code that calls GetDataReader then calls Close() on the DataReader that comes back, otherwise, it "locks" the Connection with this: 所以,我必须确保调用GetDataReader的代码然后在返回的DataReader上调用Close(),否则,它将“锁定”Connection:

There is already an open DataReader associated with this Command which must be closed first. 已经有一个与此命令关联的打开DataReader,必须先关闭它。

How can I "detach" the DataReader before I send it back from GetDataReader? 在从GetDataReader发回DataReader之前,如何“分离”DataReader? Either that, or clone it and send back the clone? 要么是,要么克隆它并发回克隆? I don't want to have to make the calling code always explicitly close it. 我不想让调用代码总是明确地关闭它。

There has to be a best practice here. 这里必须有一个最好的做法。

Update: 更新:

Thanks everyone for your input. 谢谢各位的意见。 The bottom line is that I need to lose the habit of using DataReaders and switch to DataTables. 最重要的是,我需要失去使用DataReaders并切换到DataTables的习惯。 They're much more manageable. 它们更易于管理。

Also, thanks for the note on connection pooling. 另外,感谢有关连接池的说明。 I knew about it, but just didn't put two and two together and realize I was re-inventing the wheel. 我知道它,但只是没有把两个和两个放在一起,并意识到我正在重新发明轮子。

DataReader's must stay connected to the db until you no longer need them - that's the nature of using a DataReader so you can't "disconnect" them as such. DataReader必须保持与数据库的连接,直到您不再需要它们为止 - 这就是使用DataReader的本质,因此您无法“断开”它们。 When you're finished with a data reader, you should close it ( .Close() ) but then you can't use it any more. 当你完成数据阅读器时,你应该关闭它( .Close() )但是你不能再使用它了。

From .NET 2.0 on, if you're using SQL 2005 or later, you can make use of MARS (Multiple Active Result Sets) as explained here . 从.NET 2.0,如果你使用SQL 2005或更高版本,可以使用MARS (多个活动结果集)作为解释在这里 This allows you to use a single connection for multiple data readers and just involves a change to your connection string. 这允许您为多个数据读取器使用单个连接,只需更改连接字符串即可。 However, SqlDataReaders aren't ideal for passing around your code in the way it sounds like you want. 但是,SqlDataReaders并不适合以您想要的方式传递代码。

Alternatively (which is what I think you need to do), you may want to use a disconnected resultset which is where DataSet/DataTables come in. You use an SqlDataAdapter to fill a DataSet/DataTable with all the results of a query. 或者(我认为你需要这样做),你可能想要使用一个断开连接的结果集,这是DataSet / DataTables的用武之地 。你使用SqlDataAdapter用查询的所有结果填充DataSet / DataTable。 You can then use the connection for any other purpose, or close the connection, and it doesn't affect your in-memory resultset. 然后,您可以将该连接用于任何其他目的,或关闭连接,它不会影响您的内存中结果集。 You can pass your resultset around your code without needing to maintain an open database connection. 您可以在代码周围传递结果集,而无需维护开放的数据库连接。

Do not persist you database connection. 不要坚持你的数据库连接。 There is a feature called "connection pooling". 有一个称为“连接池”的功能。 Getting a fresh connection is not expensive. 获得新的连接并不昂贵。

Generally, best practice would be to use connection pooling rather than a persistent connection, to allow simultaneous access by multiple users. 通常,最佳做法是使用连接池而不是持久连接,以允许多个用户同时访问。 The only way I can think of to do what you want to do would be to load a DataSet from the reader and return that. 我能想到做你想做的事的唯一方法是从阅读器加载一个DataSet并返回它。

I think you might be getting your datasets (disconnected embedded data) and datareaders (no data) mixed up. 我想你可能会把你的数据集(断开连接的嵌入数据)和数据集(没有数据)混淆在一起。 A DataReader without a SqlCnnection is... ummm... just a Reader, ie no data ;-) 没有SqlCnnection的DataReader就是......嗯......只是一个读者,即没有数据;-)

I think your problem is further up your line of thinking. 我认为你的问题在于你的思路。 I'm guessing you're an old school programmer used to doing everything by hand. 我猜你是一个老学校的程序员,常常手工做。 In the "managed" world of dot net, many things are managed for you; 在dot net的“托管”世界中,很多东西都是为你管理的; ADO.NET has an effective data connection pooling system already, you shouldn't need to maintain your own pool. ADO.NET已经有了一个有效的数据连接池系统,你不需要维护自己的池。

-Oisin -Oisin

Here's a handy helper method to execute some SQL against a connection, and have it disconnected from the server: 这是一个方便的帮助方法,可以对连接执行一些SQL,并让它与服务器断开连接:

public static DbDataReader ExecuteReaderClient(DbConnection connection, DbTransaction transaction, String commandText)
{
    DbCommand command = connection.CreateCommand();
    command.CommandText = commandText;
    if (transaction != null)
        command.Transaction = transaction;

    DbDataAdapter adapter = DbProviderFactories.GetFactory(connection).CreateDataAdapter();

    adapter.SelectCommand = command;
    DataSet dataset = new DataSet();

    try
    {
        adapter.Fill(dataset);
    }
    catch (Exception e)
    {
        throw new Exception(
                  e.Message + "\r\n" +
                  "Command Text" + "\r\n" +
                  commandText, e);
    }

    try
    {
        return dataset.CreateDataReader();
    }
    finally
    {
        dataset.Dispose();
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM