使用嵌套命令时可以避免打开 DataReader 异常吗?

Posted

技术标签:

【中文标题】使用嵌套命令时可以避免打开 DataReader 异常吗?【英文标题】:Can I avoid the open DataReader exception when using nested commands? 【发布时间】:2009-09-01 11:39:28 【问题描述】:

在使用类似这样的构造时,我能否避免打开 DataReader 异常(“已经有一个打开的 DataReader 与此命令关联,必须先关闭。”)?

public void FirstMethod()

    using (var command = connection.CreateCommand())
    
        command.CommandText = "...";
        using (var reader = command.ExecuteReader())
        
            // do something with the data
            SecondMethod();
        
    


public void SecondMethod()

    using (var command = connection.CreateCommand())
    
        command.CommandText = "...";
        using (var reader = command.ExecuteReader()) // Exception
        
        
    

最好的问候

【问题讨论】:

【参考方案1】:

您可以使用本地连接(即方法的本地连接);使用连接池,将连接保留为字段的优势是微乎其微的,并且经常会引起这种类型的……乐趣。当然,如果您正在编辑数据,您可能会遇到阻止自己的问题——也许使用TransactionScope 之类的东西可以缓解。底部示例...

或者,您可以在连接上启用 MARS(多个活动结果集);应该这样做。只需在连接字符串中包含“MultipleActiveResultSets=True”作为一对(SQL Server 2005 及更高版本)。

public void FirstMethod() 
    using (var connection = CreateAndOpenConnection())
    using (var command = connection.CreateCommand()) 
        command.CommandText = "...";
        using (var reader = command.ExecuteReader()) 
            // do something with the data
            SecondMethod();
        
    

public void SecondMethod() 
    using (var connection = CreateAndOpenConnection())
    using (var command = connection.CreateCommand()) 
        command.CommandText = "...";
        using (var reader = command.ExecuteReader()) // Exception
         
    

private SqlConnection CreateAndOpenConnection() 
    var conn = new SqlConnection(connectionString);
    conn.Open(); // perhaps dispose if this fails...
    return conn;

【讨论】:

【参考方案2】:

为什么不直接更改方法签名?

public void FirstMethod()

    using (var command = connection.CreateCommand())
    
        command.CommandText = "...";
        using (var reader = command.ExecuteReader())
        
            // do something with the data
            SecondMethod(reader);
        
    


public void SecondMethod(var reader)

    // do stuff with reader...

这不仅避免了这个问题,而且还产生了更少的开销,因为您只创建了 1 个 command/reader 而不是 2 个。(这假设您的方法调用是同步的。)

另外,考虑使用强类型变量而不是var 关键字;引入var 是为了支持匿名类型,并且只应在必要时使用。

【讨论】:

好吧,如果第二种方法基于相同的 sql 语句,我会这样做,当然不是这样(否则,我为什么需要方法?)。 @Ian:所有变量在 C# 中都是强类型的,但是你声明它们。 (C#4 发布时将允许使用 dynamic 变量,但它们与 var 关键字无关。) 是的,var 关键字只是隐藏了具体类型,但隐含地表示了它。所以你可以写“int i = 1”和“var i = 1”,两个语句是相等的。 阅读器不是“只进”吗?因此,您将无法 // 用阅读器做事... @AMissico:DataReader 可能包含多个结果集。见NextResult方法:msdn.microsoft.com/en-us/library/…

以上是关于使用嵌套命令时可以避免打开 DataReader 异常吗?的主要内容,如果未能解决你的问题,请参考以下文章

调用另一个 repo 时出错 - '已经有一个打开的 DataReader 与此命令关联,必须先关闭'

实体框架运行时错误 - 已经有一个打开的 DataReader 与此命令关联,必须先关闭

尝试插入、更新或删除时出错:已经有一个打开的 DataReader 与此命令关联,必须先关闭

EF6 - 已经有一个打开的 DataReader 与此命令关联,必须先关闭

已经有一个与此命令关联的打开的 DataReader 必须首先关闭 linq [重复]

错误:已经有一个与此命令关联的打开DataReader,必须先关闭它。多个用户