DataReader 已打开

Posted

技术标签:

【中文标题】DataReader 已打开【英文标题】:DataReader already open 【发布时间】:2012-01-21 10:38:08 【问题描述】:

我遇到了一个错误,提示我的数据读取器已打开。

我的代码是这样的

public static Users GetByID(int ID, SqlConnection connection)
    
        SqlCommand command = new SqlCommand("Select Name, Email, LastLogin, FK_Role_ID from Users where ID=@id");
        command.Connection = connection;

        command.Parameters.Add(new SqlParameter("id", ID));

        SqlDataReader reader = command.ExecuteReader();
        if (reader.Read())
        
            Users user = new Users();
            user.ID = ID;
            user.Name = reader.GetString(0);
            user.Email = reader.GetString(1);
            user.LastLogin = reader.GetString(2);
            user.role = Role.GetRoleByID(reader.GetInt32(3), connection);
            reader.Close();
            return user;
        
        else
        
            reader.Close();
            return null;
        
    

Role.GetRoleByID 中出现错误,表明 datareader 命令已打开。这是真的,但是我如何使用我的读者提供的信息调用 Role.GetRoleByID。

我用 c# 和 ASP.NET 编写代码

【问题讨论】:

为什么不在查询中加入 GetRoleByID? 【参考方案1】:

您的Role.GetRoleByID 似乎会尝试重用该连接。

选项:

GetByID 中的SqlDataReader 获取您需要的数据,关闭该阅读器,然后然后调用Role.GetRoleByID(因此您一次只有一个活动阅读器) 启用多个活动结果集 (MARS) - 我不能说我有这方面的经验 使每个方法使用单独的连接以减少方法之间的依赖关系。请注意,连接池将使打开/关闭变得相当便宜。

如果我是你,我会选择第一个选项 - 或者可能是最后一个。我还会使用using 语句自动关闭阅读器:

private const string GetUserByIdSql =
    "Select Name, Email, LastLogin, FK_Role_ID from Users where ID=@id";

public static Users GetByID(int ID, SqlConnection connection)

    var sql = ;
    Users user;
    int roleId;
    using (var command = new SqlCommand(GetUserByIdSql, connection))
    
        command.Parameters.Add(new SqlParameter("id", ID));
        using (var reader = command.ExecuteReader())
        
            if (!reader.Read())
            
                return null;
            
            user = new Users
            
                Name = reader.GetString(0),
                Email = reader.GetString(1),
                LastLogin = reader.GetString(2),
            ;
            // Remember this so we can call GetRoleByID after closing the reader
            roleID = reader.GetInt32(3);
        
    
    user.Role = Role.GetRoleByID(roleID, connection);
    return user;

作为第四个选项 - 为什么不在现有查询中执行 GetRoleByID 所需的连接?这意味着您只需访问数据库一次。

【讨论】:

在我的代码中,如果读者不阅读,则返回 null 是一个后备。在您上面的代码中,即使读者没有阅读,返回用户也是如此。这将如何影响 null 结果? @MichaelTotKorsgaard:再看一遍:if (!reader.Read()) return null; 是的,但最后你写了返回用户,不会覆盖返回空值吗? @MichaelTotKorsgaard:呃,不。当您返回时,您已经返回...它没有到达第二个返回语句。 @MichaelTotKorsgaard,C# 基础知识,伙计!【参考方案2】:

您可以考虑使用带有必要连接的 Select 查询,以便能够从同一查询中接收 Role。

另外,建议使用(using reader = command.ExecuteReader() ),这样一旦作用域结束就关闭阅读器并处理掉。

【讨论】:

【参考方案3】:

您是否允许 MARS 您的连接字符串 (MultipleActiveResultSets=true)?

【讨论】:

以上是关于DataReader 已打开的主要内容,如果未能解决你的问题,请参考以下文章

如何避免 MSSql 2000 中出现错误“已存在与此命令关联的打开 DataReader”

ASP.NET MVC 项目中 ADO.NET 实体模型的已打开 DataReader

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

Datareader 已在视图中打开,复杂对象

如何解决实体框架打开 DataReader 问题

由于我的查询,DataReader 仍然打开