2

下面是使用 Dapper.Net 在 DAL 中调用数据的示例:

    /// <summary>
    /// Handles db connectivity as Dapper assumes an existing connection for all functions
    /// Since the app uses three databases, pass in the connection string for the required db.
    /// </summary>
    /// <returns></returns>
    protected static IDbConnection OpenConnection(string connectionStringName)
    {
        try
        {
            connection = new SqlConnection(WebConfigurationManager.ConnectionStrings[connectionStringName].ConnectionString);
            //connection = SqlMapperUtil.GetOpenConnection(connectionStringName);       // if we want to use the Dapper utility methods
            //connection = new SqlConnection(connectionString);
            connection.Open();
            return connection;
        }
        catch (Exception ex)
        {
            ErrorLogging.Instance.Fatal(ex);        // uses singleton for logging
            return null;
        }
    }


    public string GetNickname(int profileID)
    {
        string nickname = string.Empty;

        using (IDbConnection connection = OpenConnection("PrimaryDBConnectionString"))
        {
            try
            {
                var sp_nickname = connection.Query<string>("sq_mobile_nickname_get_by_profileid", new { profileID = profileID }, commandType: CommandType.StoredProcedure);
                nickname = sp_nickname.First<string>();
            }
            catch (Exception ex)
            {
                ErrorLogging.Instance.Fatal(ex);
                return null;
            }
        }

        return nickname;
    }

我们看到的一致错误如下:

2012-06-20 11:42:44.8903|致命|已经有一个打开的 DataReader 与此命令关联,必须先关闭。| 在 System.Data.SqlClient.SqlInternalConnectionTds.ValidateConnectionForExecute(SqlCommand 命令) 在 System.Data.SqlClient.SqlConnection.ValidateConnectionForExecute(String 方法,SqlCommand 命令) 在 System.Data.SqlClient.SqlCommand.ValidateCommand(String 方法,布尔异步) 在 System System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method) 在系统。 Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior 行为,
在 MyApp.DAL.DapperORM.SqlMapper.d_ 13 1.MoveNext() in C:\Projects\Git\MyApp\MyApp.DAL\MyApp.DAL.MyAppPrimary.Repositories\Dapper\SqlMapper.cs:line 581 at System.Collections.Generic.List1..ctor(IEnumerable 1 collection) at System.Linq.Enumerable.ToList[TSource](IEnumerable1 源) 在 MyApp.DAL.DapperORM.SqlMapper.Query[T](IDbConnection cnn, String sql, Object param, IDbTransaction transaction, Boolean buffered, Nullable 1 commandTimeout, Nullable1 commandType) 在 C:\Projects\Git\MyApp\MyApp.DAL\MyApp.DAL.MyAppPrimary.Repositories\Dapper\SqlMapper.cs:C 中 MyApp.DAL.Repositories.MemberRepository.AddNotificationEntry(NewsfeedNotification notificationEntry) 的第 538 行: \Projects\Git\MyApp\MyApp.DAL\MyApp.DAL.MyAppPrimary.Repositories\MemberRepositories\MemberRepository.cs:line 465 2012-06-20 11:42:45.2491|致命|当阅读器关闭时调用读取无效。 | 在 System.Data.SqlClient.SqlDataReader.ReadInternal(布尔 setTimeout)
在 System.Data.SqlClient.SqlDataReader.Read() 在 MyApp.DAL.DapperORM.SqlMapper.d
_13 1.MoveNext() in C:\Projects\Git\MyApp\MyApp.DAL\MyApp.DAL.MyAppPrimary.Repositories\Dapper\SqlMapper.cs:line 597 at System.Collections.Generic.List1..ctor(IEnumerable 1 collection) at System.Linq.Enumerable.ToList[TSource](IEnumerable1 源) 在 MyApp.DAL.DapperORM.SqlMapper.Query[T](IDbConnection cnn, String C:\Projects\Git\MyApp\MyApp.DAL\MyApp.DAL.MyAppPrimary.Repositories\Dapper\SqlMapper.cs 中的sql、对象参数、IDbTransaction 事务、布尔缓冲、可空1 commandTimeout, Nullable1 命令类型):MyApp.DAL 的第 538 行。 DapperORM.SqlMapper.Query(IDbConnection cnn, String sql, Object param, IDbTransaction transaction, Boolean buffered, Nullable1 commandTimeout, Nullable1 commandType) 在 C:\Projects\Git\MyApp\MyApp.DAL\MyApp.DAL.MyAppPrimary.Repositories\Dapper\SqlMapper.cs:C 中 MyApp.DAL.Repositories.MemberRepository.GetBuddies(Int32 profileID) 的第 518 行: \Projects\Git\MyApp\MyApp.DAL\MyApp.DAL.MyAppPrimary.Repositories\MemberRepositories\MemberRepository.cs:line 271 2012-06-20 11:43:01.2392|致命|序列不包含元素| 在 System.Linq.Enumerable.First[TSource](IEnumerable`1 源) 在 C:\Projects\Git\MyApp\MyApp.DAL\MyApp.DAL.MyAppPrimary 中的 MyApp.DAL.Repositories.MemberRepository.GetNickname(Int32 profileID) .Repositories\MemberRepositories\MemberRepository.cs:第 337 行

最初我将退货放在里面using {...}并将它们移到using街区外,但仍然遇到同样的问题。

这是一个高流量的应用程序,所以在测试这个问题直到我们上线后才真正出现。

对于使用 Dapper 进行 DataReader 管理,这里还有其他事情要做吗?

- - - 更新 - - -

我应该早点发布这个,但现在才添加这个。

Dapper.Net 的第 581 行包含ExecuteReader()代码:

   private static IEnumerable<T> QueryInternal<T>(this IDbConnection cnn, string sql, object param, IDbTransaction transaction, int? commandTimeout, CommandType? commandType)
    {
        var identity = new Identity(sql, commandType, cnn, typeof(T), param == null ? null : param.GetType(), null);
        var info = GetCacheInfo(identity);

        using (var cmd = SetupCommand(cnn, transaction, sql, info.ParamReader, param, commandTimeout, commandType))
        {
            using (var reader = cmd.ExecuteReader())
            {
                Func<Func<IDataReader, object>> cacheDeserializer =  () =>
                {
                    info.Deserializer = GetDeserializer(typeof(T), reader, 0, -1, false);
                    SetQueryCache(identity, info);
                    return info.Deserializer;
                };

                if (info.Deserializer == null)
                {
                    cacheDeserializer();
                }

                var deserializer = info.Deserializer;

                while (reader.Read())
                {
                    object next;
                    try
                    {
                        next = deserializer(reader);
                    }
                    catch (DataException)
                    {
                        // give it another shot, in case the underlying schema changed
                        deserializer = cacheDeserializer();
                        next = deserializer(reader);
                    }
                    yield return (T)next;
                }

            }
        }

...在嵌套using代码中看到它?我想知道是否由于yield return (T)next;while 内部的代码,嵌套的内部using,是否会导致问题。

问题是,在流量适中的情况下,Dapper 似乎运行良好。然而,在一个每秒大约有 1000 个请求的系统中,它似乎会出错。

我想这对于 Dapper 开发者来说更​​像是一个仅供参考,并且想知道他们是否可以解决这个问题。

(我意识到我在代码中错过了命名 DapperORM - 它不是 ORM)

4

4 回答 4

1

您只读取数据读取器的第一行,因此如果有不止一行,它永远不会关闭。

于 2012-08-08T13:41:33.310 回答
0

我使用 Entity Framework 来生成我的类,因此并为 DAL 访问创建了一个不同的存储库 - 而不是使用 Dapper,我只是重写了访问代码以使用 Entity Framework。using与 EF 连接字符串和在我的语句中使用 EF 数据库上下文没有什么不同。

这一切都很好。

根据我的阅读,Dapper 非常快,这就是我最初为我的 DAL 选择它的原因。但是,它似乎在高频交易环境中有其局限性。也许 Dapper 团队可以澄清这一点,以防我遗漏了某些东西或错误地实施了某些东西。

于 2012-06-22T15:14:24.207 回答
0

Ladislav Mrnka 对类似问题的回答更有意义:

如果您在迭代另一个查询的结果时执行查询,则可能会发生这种情况......可能导致这种情况的一件事是在迭代某些查询的结果时触发延迟加载。这可以通过在连接字符串中允许 MARS 轻松解决。将 MultipleActiveResultSets=true 添加到连接字符串的提供者部分(其中指定了数据源、初始目录等)。

https://stackoverflow.com/a/6064422/1681490

有关火星的更多信息:http: //msdn.microsoft.com/en-us/library/h32h3abf (v=vs.100).aspx

于 2014-11-17T18:58:19.767 回答
0

聚会有点晚了,但它可能会帮助像我一样被卡住的人。

问题是 Dapper “Query” 方法返回的 IEnumerable 实际上是使用 “yield return” 语句来生成结果集的迭代器:

// From Dapper SqlMapper.cs QueryImpl function:
            while (reader.Read())
            {
                object val = func(reader);
                if (val == null || val is T)
                {
                    yield return (T)val;
                }
                else
                {
                    yield return (T)Convert.ChangeType(val, convertToType, CultureInfo.InvariantCulture);
                }
            }

关闭 DataReader 的部分稍后发生。因此,如果您不遍历整个结果集并尝试查询另一个请求,您将收到“已经有一个打开的 DataReader 与此命令关联,必须先关闭”错误。

于 2019-07-30T19:55:02.120 回答