高トラフィックシナリオでDapper.Netを使用している間にOpen DataReaderの問題が解決しましたか?

asp.net c#-4.0 dapper datareader dbdatareader

質問

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.SqlCommand.ValidateCommand(Stringメソッド、Boolean async)のSystem.Data.SqlClient.SqlInternalConnectionTds.ValidateConnectionForExecute(SqlCommandコマンド)のSystem.Data.SqlClient.SqlConnection.ValidateConnectionForExecute(Stringメソッド、SqlCommandコマンド) System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior、RunBehavior runBehavior、Boolean returnStream、Stringメソッド、DbAsyncResult result)。Systemで.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior、RunBehavior runBehavior、Boolean returnStream、Stringメソッド)。 Data.SqlClient.SqlCommand.ExecuteReader(CommandBehaviorビヘイビア、Stringメソッド)System.Data.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehaviorビヘイビア)System.Data.Common.DbCommand.System.Data.IDbCommand.ExecuteReader()
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.List MyApp.DAL.DapperORM.SqlMapper.Query(IDbConnection cnn、String sql、Object 1 collection) at System.Linq.Enumerable.ToList[TSource](IEnumerable 1ソース)の1..ctor(IEnumerable 1 collection) at System.Linq.Enumerable.ToList[TSource](IEnumerable C#\ Projects \ Git \ MyApp \ MyApp.DAL \ MyApp.DAL.MyAppPrimary.Repositories \ Dapper \ SqlMapper.cs:MyApp.DALの行538で、バッファリングされたブール型、Nullable 1 commandTimeout, Nullable 1 commandType) C:\ Projects \ Git \ MyApp \ MyApp.DAL \ MyApp.DAL.MyAppPrimary.Repositories \ MemberRepositories \ MemberRepository.csの.Repositories.MemberRepository.AddNotificationEntry(NewsfeedNotification notificationEntry):行465 2012-06-20 11:42:45.2491 | Fatal |リーダーが閉じられているときにReadを呼び出す試みが無効です。 System.Data.SqlClient.SqlDataReader.ReadInternal(Boolean setTimeout)
1.MoveNext() in C:\Projects\Git\MyApp\MyApp.DAL\MyApp.DAL.MyAppPrimary.Repositories\Dapper\SqlMapper.cs:line 597 at System.Collections.Generic.List でのSystem.Data.SqlClient.SqlDataReader.Read()での1.MoveNext 1.MoveNext() in C:\Projects\Git\MyApp\MyApp.DAL\MyApp.DAL.MyAppPrimary.Repositories\Dapper\SqlMapper.cs:line 597 at System.Collections.Generic.List行597. MyApp.DAL.DapperORM.SqlMapperの1 collection) at System.Linq.Enumerable.ToList[TSource](IEnumerable 1ソース)の1..ctor(IEnumerable 1 collection) at System.Linq.Enumerable.ToList[TSource](IEnumerable 。 C:\ Projects \ Git \ MyApp \ MyApp.DAL \ MyApp.DAL.MyAppPrimary.Repositories \に、クエリ[T](IDbConnection cnn、String sql、Object param、IDbTransactionトランザクション、ブールバッファリング、Nullable 1 commandTimeout, Nullable 1 commandType) C:\ Projects \ Git \ System32内のMyApp.DAL.DapperORM.SqlMapper.Query(IDbConnection cnn、String sql、Object param、IDbTransactionトランザクション、ブールバッファリング、Nullable 1 commandTimeout, Nullable 1 commandType)の行538、Dapper \ SqlMapper.cs: MyApp \ MyApp.DAL \ MyApp.DAL.MyAppPrimary.Repositories \ Dapper \ SqlMapper.cs:C:\ Projects \ Git \ MyApp \ MyApp.DAのMyApp.DAL.Repositories.MemberRepository.GetBuddies(Int32 profileID)の行518 L \ MyApp.DAL.MyAppPrimary.Repositories \ MemberRepositories \ MemberRepository.cs:line 271 2012-06-20 11:43:01.2392 |致命的|シーケンスに要素が含まれていません| C:\ Projects \ Git \ MyApp \ MyApp.DAL \ MyApp.DAL.MyAppPrimaryのMyApp.DAL.Repositories.MemberRepository.GetNickname(Int32 profileID)のSystem.Linq.Enumerable.First [TSource](IEnumerable`1ソース) .Repositories \ MemberRepositories \ MemberRepository.cs:337行目

当初は、 using {...}中に戻り値を持ち、 usingブロックの外側に移動しましたが、同じ問題が発生しています。

これはトラフィックの多いアプリケーションであるため、テストする際には、この問題は実際にライブになるまで現れませんでした。

Dapperを使ってDataReaderを管理するためにここで行わなければならないことがありますか?

----- UPDATE -----

私はこれを以前に投稿していたはずですが、これを今追加するだけです。

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;ためにかどうか疑問に思いyield return (T)next;中にコードを入れて、ネストされたusingで、それが問題の原因になっている場合。

問題は、適度な量のトラフィックで、Dapperはうまく動作しているようです。しかし、1秒あたり約1000件のリクエストを持つシステムでは、それは上がるようです。

私はこれがDapperの開発者のためのFYIの詳細であり、彼らがこれを解決できるかどうか疑問に思っています。

(そして私はDapperORMという名前がコードに間に合わなかったことを認識しています - それはORMではありません)

受け入れられた回答

私はクラスを生成するためにEntity Frameworkを使用していましたので、Dalアクセス用の別のリポジトリを作成しました.Operityを使用するのではなく、Entity Frameworkを使用するアクセスコードを書き換えました。 EF接続文字列と異なるものと、 usingステートメントでEFデータベースコンテキストを使用するものはありません。

それはすべて正常に動作します。

私が読んだところでは、Dapperはかなり高速です。なぜ私は最初にDALでこれを選択したのですか?しかし、それは高頻度のトランザクション環境には限界があるようです。おそらくDapperチームは、何かを見逃した場合や、何かを間違って実装した場合にこれを明確にすることができます。


人気のある回答

あなたは、データレアの最初の行だけを読むので、複数の行がある場合は決して閉じられません。



ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ
ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ