【问题标题】:Dapper giving "Invalid attempt to call FieldCount when reader is closed." when trying to use "QueryMultiple"Dapper 给出“当阅读器关闭时调用 FieldCount 的尝试无效。”尝试使用“QueryMultiple”时
【发布时间】:2016-01-04 05:04:30
【问题描述】:

我有一个 Dapper.NET 的 QueryMultiple 方法的包装方法。它成功地从一个存储过程中获取数据,该存储过程有 3 个查询,它们都是SELECT 查询。但是获取数据后,我无法使用ReadReadAsync 将数据分配给类变量。我在下面附上我的代码。

public Tuple<IEnumerable<T1>, IEnumerable<T2>, IEnumerable<T3>> 
        QueryMultiple<T1, T2, T3>()
    {
        try
        {
            var data = MultiQuery("[App].[USP_GetAllCategories]");
            var category = data.Read<T1>();
            var subcategory = data.Read<T2>();
            var subSubcategory = data.Read<T3>();
            return new Tuple<IEnumerable<T1>, IEnumerable<T2>, IEnumerable<T3>>(
                category, subcategory, subSubcategory);
        }
        catch (Exception)
        {
            return null;
        }
    }

    public SqlMapper.GridReader MultiQuery(string storedProcedureName)
    {
        using (var connection = LocalConnection())
        {
            try
            {
                return connection.QueryMultiple(
                    sql: storedProcedureName,
                    commandType: CommandType.StoredProcedure);
            }
            catch (Exception)
            {
                return null;
            }
            finally
            {
                CloseConnection(connection);
            }
        }
    }

【问题讨论】:

  • 您在调用Read 之前就已经处理了连接。我不确定 dapper 是否会立即加载数据,但无论如何代码看起来都是错误的.. 没有一个很好的理由来拥有一个简单地为您包装 using 的方法。只需将using 块放入QueryMultiple
  • @Rob 供参考:不,它没有(至少在这种情况下也没有);它基本上包装了一个开放的IDataReader
  • @Rob 我认为在处理连接后,我仍然可以使用GridReader 从中读取数据。但正如你所看到的,它似乎不起作用。我创建了MultiQuery,这样其他开发人员就不需要知道如何查询,只需使用GridReader 来获取数据。
  • @haider_kazal 无法保证读者在关闭连接后仍然有效;它是一个开放阅读器——我们实际上还没有从 TDS 流中消费任何数据
  • 好的...谢谢@MarcGravell

标签: c# asp.net-web-api2 dapper


【解决方案1】:

查看您的MultiQuery 方法。特别是查看finally 块。现在考虑:在数据被消耗之前,该块已被调用。基本上,不要那样做。

如果是我:

using (var connection = LocalConnection())
uaing (var data = conn.QueryMultiple("[App].[USP_GetAllCategories]",
    command type: CommandType.StoredProcedure))
{
    //... Consume
}

如果编写一个添加命令类型的QueryMultipleSP 扩展方法有帮助,那么也许可以这样做,但是...

【讨论】:

  • 您好,谢谢您的回答。但是问题是,我需要编写MultiQuery 函数,这样开发人员就不需要知道数据库的细节,只需要一个GridReader,他们可以从中Read 数据。我想这是不可能的。
  • 如果你想返回一个阅读器,你需要让你的代码的客户端负责处理阅读器和连接。您需要在 API 文档中正确记录这一点。而且,您不能在 IDisposables 上使用“使用”。您可以在您的类本身中实现您想要实现的 IDisposable,并在您的 Dispose 实现中处理您的依赖项。但是,我猜这是 API 设计的问题。
  • @haider_kazal 你可以这样做,但你需要包装 GridReader 并使读者有责任关闭/处理连接并处理包装的GridReader
  • 您可以将 MultiQuery 包装在具有回调参数的包装方法中:Func&lt;SqlMapper.GridReader,T&gt; callback。包装器方法将返回对 using 块内的回调的调用。它确保连接始终正确关闭/处理,并且客户端代码可以使用GridReader 完成所需的操作。
  • @goPlayerJuggler 回答是最正确的方法。我花了一点时间来解决它,但它保留了 OP 的要求。他的开发人员无需处理 sql 连接即可进行查询的无缝方式。
猜你喜欢
  • 2011-03-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-17
  • 2021-08-29
  • 1970-01-01
相关资源
最近更新 更多