C# 如何判断SqlConnection是否连接了SqlDataReader?

C# 如何判断SqlConnection是否连接了SqlDataReader?,c#,.net,sql,ado.net,C#,.net,Sql,Ado.net,现在,这更多的是好奇,而不是实际目的。如果您打开了一个SqlConnection并将SqlDataReader附加到它,然后尝试使用相同的SqlConnection运行另一个查询,那么它将抛出一个错误。我的问题是SqlConnection如何知道有读卡器连接到它。HasDataReader没有公共属性或任何东西,那么SqlConnection类是如何知道的呢 原始问题:(不再相关) 大家好,我正在为连接池设置一个小东西,以及我们遇到的一些更常见的错误(它总是很容易修复,但我们就是记不起read

现在,这更多的是好奇,而不是实际目的。如果您打开了一个
SqlConnection
并将
SqlDataReader
附加到它,然后尝试使用相同的
SqlConnection
运行另一个查询,那么它将抛出一个错误。我的问题是
SqlConnection
如何知道有读卡器连接到它。
HasDataReader
没有公共属性或任何东西,那么
SqlConnection
类是如何知道的呢


原始问题:(不再相关)

大家好,我正在为连接池设置一个小东西,以及我们遇到的一些更常见的错误(它总是很容易修复,但我们就是记不起
reader.Close()
!)就是当我们有一个被很多类/方法使用的连接时,一个方法打开一个数据读取器却忘记关闭它。这并不是很糟糕,因为很多时候,你所要做的就是进入调试器,上升一个级别,查看之前的函数,检查它是否有未关闭的数据读取器

现在,更大的问题来了。在这个连接池中,如果一个数据读取器是打开的,那么直到一个线程获得一个连接并尝试使用它,它才被知道,而最初打开数据读取器的东西可能不再是活动的


因此,非常简单,您如何检测数据读取器是否在连接上打开,是否有方法在不关闭连接的情况下关闭读取器

确保关闭DataReader(和数据库连接)的方法是始终在using块中打开它们,如下所示:

using (SqlDataReader rdr = MySqlCommandObject.ExecuteReader())
{
    while (rdr.Read())
    {
        //...
    }
} // The SqlDataReader is guaranteed to be closed here, even if an exception was thrown.

为了避免这种情况,请将DataReader包装在using块中,这将保证它像这样处理连接:

using (IDataReader reader = command.ExecuteReader())
{
      //do stuff
}

IDataReader上有一个名为IsClosed的属性,它会告诉你它的状态

检查它是否打开,如果打开,请关闭它。请注意,如果您使用的是SqlHelper类,这是一个bug-在某些情况下它不会关闭连接。解决方案是在代码中使用try/catch或using块,这取决于您是否是2.0之前的版本。

如果出于任何原因无法使用using子句,您也可以使用委托,下面是一个如何实现这一点的示例:

public delegate void TransactionRunner(DbConnection sender, DbTransaction trans, object state);

public void RunTransaction(TransactionRunner runner, object state)
    {
        RunTransaction(runner, IsolationLevel.ReadCommitted, state);
    }

public void RunTransaction(TransactionRunner runner, IsolationLevel il, object state)
    {

        DbConnection cn = GetConnection from pool
        DbTransaction trans = null;

        try
        {  
            trans = cn.BeginTransaction(il);
            runner(cn, trans, state);
            trans.Commit();
        }
        catch (Exception err)
        {
            if (trans != null)
                trans.Rollback();
            throw err;
        }
        finally
        {
            //Here you can close anything that was left open
        }
    }
然后,当您需要使用它时,只需使用函数并将函数作为

public void DoStuff(){
    TransactionRunner tr = new TransactionRunner(MyFunction);
    RunTransaction(tr, <a parameter>);
}
public void DoStuffInternal(DbConnection cn, DbTransaction trans, object state){
    //Do Stuff and Im sure that the transaction will commit or rollback
}
public void DoStuff(){
TransactionRunner tr=新的TransactionRunner(MyFunction);
运行事务(tr,);
}
public void DoStuffInternal(DbConnection cn、DbTransaction trans、对象状态){
//做一些事情,我确信事务会提交或回滚
}

在.NET3.5中,这似乎是一个过度的操作,但在.NET1.0中,我们就是这样做的。。。希望能有帮助……

没有人真正回答厄尔兹的问题。(“你为什么这样做?”这不是答案。)我认为答案是,你不能仅仅通过查看连接本身来判断连接是否有与之关联的开放数据读取器。连接不会公开任何会告诉您这一点的属性。打开连接将其状态属性设置为ConnectionState.Open。在其上打开数据读取器不会更改连接状态。像ConnectionState.Fetching这样的状态值仅在数据操作(如SqlDataReader.Read()正在进行)时使用。当连接处于读取之间时,连接状态就是打开的。因此,要确定打开的读卡器何时使用连接,必须检查可能正在使用连接的读卡器的状态

今天我也遇到了同样的情况,但是。。。网络上没有运气

因此,我编写了下面的代码来查找读卡器是否在连接中打开,或者通常查找连接是否已准备好使用:

private bool IsConnectionReady(SqlConnection Connection)
{
    bool nRet = true;

    try
    {
        String sql = "SELECT * FROM dummy_table";

        using (SqlCommand cmd = new SqlCommand(sql, Connection))
        {
            using (SqlDataReader rdr = cmd.ExecuteReader())
            { }
        }
    }
    catch (Exception ex)
    {
        nRet = false;
    }

    return nRet;
}
“dummy_table”是my db中用于检查可访问性的空虚拟表

这只是一个解决办法,但我应该让事情的工作,并能够在任何情况下检查连接可用性

因此,我希望它能对您有所帮助。

根据,您应该始终在完成后关闭读卡器,即使您使用的是using块。使用块将关闭连接,但不会关闭读卡器。为什么不一致?我不知道

SqlConnection如何知道 读者是附在它上面的

就我所见,SQLConnection知道它有一个附加的读卡器,因为它在内部维护对它的引用

明智地使用Reflector表明SQLConnection对象有一个类型为DBConnectionInternal的私有字段,该字段由这个抽象类的许多具体实现之一填充。当您尝试将第二个live reader添加到连接时,会对内部连接调用“ValidateConnectionForExecute”方法,这将跟踪到对内部“ReferenceCollection”的检查。当显示现有的实时阅读器时,将引发异常

我想,如果您愿意,您可以在运行时使用反射来挖掘所有这些

然后尝试使用相同的SqlConnection运行另一个查询,它将抛出一个错误


当然,您可以启用-然后它不会抛出。当然有一些限制(不总是存在吗?),但它会起作用。当然,这只适用于嵌套操作。如果问题是您不小心留下了打开的东西(您应该已经关闭了),那么答案是(如前所述)
使用

哇。。很多人没有回答这个问题!没有人提到的是多线程应用程序。我想这里的每个人都知道,你必须关闭阅读器,但我似乎没有看到任何人提出这样一个事实:当下一个请求到来时,阅读器可能无法完成。例如我有一个通过单独的线程填充的表,以便保留UI交互。让第二个、第三个和第四个线程等待