このコマンドに関連付けられた開いているDataReaderがすでに存在するため、最初に閉じる必要があります


640

私はこのクエリを持っていて、この関数でエラーが発生します:

var accounts = from account in context.Accounts
               from guranteer in account.Gurantors
               select new AccountsReport
               {
                   CreditRegistryId = account.CreditRegistryId,
                   AccountNumber = account.AccountNo,
                   DateOpened = account.DateOpened,
               };

 return accounts.AsEnumerable()
                .Select((account, index) => new AccountsReport()
                    {
                        RecordNumber = FormattedRowNumber(account, index + 1),
                        CreditRegistryId = account.CreditRegistryId,
                        DateLastUpdated = DateLastUpdated(account.CreditRegistryId, account.AccountNumber),
                        AccountNumber = FormattedAccountNumber(account.AccountType, account.AccountNumber)
                    })
                .OrderBy(c=>c.FormattedRecordNumber)
                .ThenByDescending(c => c.StateChangeDate);


public DateTime DateLastUpdated(long creditorRegistryId, string accountNo)
{
    return (from h in context.AccountHistory
            where h.CreditorRegistryId == creditorRegistryId && h.AccountNo == accountNo
            select h.LastUpdated).Max();
}

エラーは:

このコマンドに関連付けられている開いているDataReaderが既に存在するため、最初に閉じる必要があります。

更新:

追加されたスタックトレース:

InvalidOperationException: There is already an open DataReader associated with this Command which must be closed first.]
   System.Data.SqlClient.SqlInternalConnectionTds.ValidateConnectionForExecute(SqlCommand command) +5008639
   System.Data.SqlClient.SqlConnection.ValidateConnectionForExecute(String method, SqlCommand command) +23
   System.Data.SqlClient.SqlCommand.ValidateCommand(String method, Boolean async) +144
   System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result) +87
   System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method) +32
   System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method) +141
   System.Data.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehavior behavior) +12
   System.Data.Common.DbCommand.ExecuteReader(CommandBehavior behavior) +10
   System.Data.EntityClient.EntityCommandDefinition.ExecuteStoreCommands(EntityCommand entityCommand, CommandBehavior behavior) +443

[EntityCommandExecutionException: An error occurred while executing the command definition. See the inner exception for details.]
   System.Data.EntityClient.EntityCommandDefinition.ExecuteStoreCommands(EntityCommand entityCommand, CommandBehavior behavior) +479
   System.Data.Objects.Internal.ObjectQueryExecutionPlan.Execute(ObjectContext context, ObjectParameterCollection parameterValues) +683
   System.Data.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption) +119
   System.Data.Objects.ObjectQuery`1.System.Collections.Generic.IEnumerable<T>.GetEnumerator() +38
   System.Linq.Enumerable.Single(IEnumerable`1 source) +114
   System.Data.Objects.ELinq.ObjectQueryProvider.<GetElementFunction>b__3(IEnumerable`1 sequence) +4
   System.Data.Objects.ELinq.ObjectQueryProvider.ExecuteSingle(IEnumerable`1 query, Expression queryRoot) +29
   System.Data.Objects.ELinq.ObjectQueryProvider.System.Linq.IQueryProvider.Execute(Expression expression) +91
   System.Data.Entity.Internal.Linq.DbQueryProvider.Execute(Expression expression) +69
   System.Linq.Queryable.Max(IQueryable`1 source) +216
   CreditRegistry.Repositories.CreditRegistryRepository.DateLastUpdated(Int64 creditorRegistryId, String accountNo) in D:\Freelance Work\SuperExpert\CreditRegistry\CreditRegistry\Repositories\CreditRegistryRepository.cs:1497
   CreditRegistry.Repositories.CreditRegistryRepository.<AccountDetails>b__88(AccountsReport account, Int32 index) in D:\Freelance Work\SuperExpert\CreditRegistry\CreditRegistry\Repositories\CreditRegistryRepository.cs:1250
   System.Linq.<SelectIterator>d__7`2.MoveNext() +198
   System.Linq.Buffer`1..ctor(IEnumerable`1 source) +217
   System.Linq.<GetEnumerator>d__0.MoveNext() +96

回答:


1287

これは、別のクエリの結果を反復しながらクエリを実行した場合に発生する可能性があります。例が完全ではないため、これがどこで発生するかは、例から明確ではありません。

これを引き起こす可能性のあるものの1つは、クエリの結果を反復するときにトリガーされる遅延読み込みです。

これは、接続文字列でMARSを許可することで簡単に解決できます。MultipleActiveResultSets=true接続文字列のプロバイダー部分に追加します(データソース、初期カタログなどが指定されています)。


34
これでうまくいきました。複数のアクティブな結果セット(MARS)の有効化の詳細については、msdn.microsoft.com/ en- us/library/h32h3abf ( v=vs.100 ) .aspxを参照してください。MARSのデメリットにまで読んで考えてみましょうあまりにもstackoverflow.com/questions/374444/...
Digantaクマール

3
パフォーマンスを考慮に入れると、System.Data.Entityをインクルードし、次にIncludeステートメントを使用してこのセカンダリデータが元のクエリに読み込まれるようにすることで、これを解決することもできます。MARSを有効にした場合、これをオフにしてこれらの繰り返されるデータロードをチェックすると、ラウンドトリップが減少するため、データ処理の呼び出しを高速化できます。
Chris Moschini、

70
MARSを有効にするのは、問題/ユースケースのごく一部に限定してください。ほとんどの場合、問題のエラーは、呼び出し側アプリケーション内の不良コードが原因です。ここでは詳細:devproconnections.com/development/...
マイケル・K.キャンベル

132
your.Include()。Where()の後に.ToList()を追加すると、問題が解決する可能性があります。
Serj Sagan 2013

2
1つのクエリに対してグローバルSQL接続全体を変更するのはばかげています。正解は以下のToListです。ローカライズされた問題のローカル修正(つまり、クエリを変更するだけ)!
bytedev

218

ステートメントのToList()前にメソッドを使用できますreturn

var accounts =
from account in context.Accounts
from guranteer in account.Gurantors

 select new AccountsReport
{
    CreditRegistryId = account.CreditRegistryId,
    AccountNumber = account.AccountNo,
    DateOpened = account.DateOpened,
};

 return accounts.AsEnumerable()
               .Select((account, index) => new AccountsReport()
                       {
                           RecordNumber = FormattedRowNumber(account, index + 1),
                           CreditRegistryId = account.CreditRegistryId,
                              DateLastUpdated = DateLastUpdated(account.CreditRegistryId, account.AccountNumber),
                           AccountNumber = FormattedAccountNumber(account.AccountType, account.AccountNumber)}).OrderBy(c=>c.FormattedRecordNumber).ThenByDescending(c => c.StateChangeDate).ToList();


 public DateTime DateLastUpdated(long creditorRegistryId, string accountNo)
    {
        var dateReported = (from h in context.AccountHistory
                            where h.CreditorRegistryId == creditorRegistryId && h.AccountNo == accountNo
                            select h.LastUpdated).Max();
        return dateReported;
    }

9
私はこのエラーを何度も経験しています...そして忘れるたびに!質問への答えは常にToList()を使用することです。
Cheesus Toast 2015

1
これには欠点がありますか?10万行ある場合、これは良いことではないかと思います。
Martin Dawson

2
@MartinMazzaDawson、本当に一度にクエリ実行に100Kレコードが必要ですか?私は、ページネーションを使用することがこの状況に適していると思います
kazem

古いトピックを提起して申し訳ありませんが、RepositoryPatternの開発中に同じエラーが発生し、リポジトリのすべてのメソッドに「.ToList()or Single()or Count()」を追加することで解決しました。最初は「.AsEnumerable()」を返していました。さて、私の質問は:リポジトリが "ToList()"を返す必要があるのか​​、それとも最終消費者(つまり、サービス/ビジネスロジック)に要求されるものなのか
alessalessio

私のために働く。.ToListを追加すると、JetEntityFrameworkProviderの10進サポートの問題が解決されます。Total = storeDb.OF_Carts.Where(x => x.CartId == ShoppingCartId).ToList().Sum(t => t.Quantity * t.Item.UnitPrice);
hubert17

39

構文.ToList()を使用して、dbから読み込まれたオブジェクトをリストに変換し、再度読み込まれないようにします。これが機能することを願っています。ありがとう。


22

これは、参照が必要な人のための接続文字列です。

  <connectionStrings>
    <add name="IdentityConnection" connectionString="Data Source=(LocalDb)\v11.0;AttachDbFilename=|DataDirectory|\IdentityDb.mdf;Integrated Security=True;MultipleActiveResultSets=true;" providerName="System.Data.SqlClient" />
  </connectionStrings>

15
MARSを有効にすることは回避策であり、問​​題の解決策ではありません。
SandRock、2016年

5
MARSのドキュメントページから:「MARS操作はスレッドセーフではありません。」つまり、コンテキストにアクセスする複数のスレッドから問題が発生した場合、MARSは(おそらく)解決策ではありません。
marsop 2017年

20

私の場合、Include()このエラーを解決し、状況に応じて使用すると、結合で一度にすべてをクエリできる場合に複数のクエリを発行するよりもはるかに効率的です。

IEnumerable<User> users = db.Users.Include("Projects.Tasks.Messages");

foreach (User user in users)
{
    Console.WriteLine(user.Name);
    foreach (Project project in user.Projects)
    {
        Console.WriteLine("\t"+project.Name);
        foreach (Task task in project.Tasks)
        {
            Console.WriteLine("\t\t" + task.Subject);
            foreach (Message message in task.Messages)
            {
                Console.WriteLine("\t\t\t" + message.Text);
            }
        }
    }
}

アプリケーションがMARSを必要としない場合は、これが最良のソリューションです。
Fred Wilson、

7

これが正解かどうかわかりません。申し訳ありません。ToList()を使用して問題をどのように解決したかを困っている人に知らせたいだけです。

私の場合、以下のクエリで同じ例外が発生しました。

int id = adjustmentContext.InformationRequestOrderLinks.Where(item => item.OrderNumber == irOrderLinkVO.OrderNumber && item.InformationRequestId == irOrderLinkVO.InformationRequestId).Max(item => item.Id);

以下のように解決しました

List<Entities.InformationRequestOrderLink> links = adjustmentContext.InformationRequestOrderLinks
.Where(item => item.OrderNumber == irOrderLinkVO.OrderNumber && item.InformationRequestId == irOrderLinkVO.InformationRequestId).ToList();

int id = 0;

if (links.Any())
{
  id = links.Max(x => x.Id);
 }
if (id == 0)
{
//do something here
}

5

同じEFコンテキストを使用してアクティブなクエリ内からDateLastUpdatedを呼び出しており、DateLastUpdateがデータストア自体にコマンドを発行しているようです。Entity Frameworkは、コンテキストごとに一度に1つのアクティブコマンドのみをサポートします。

上記の2つのクエリを次のように1つにリファクタリングできます。

return accounts.AsEnumerable()
        .Select((account, index) => new AccountsReport()
        {
          RecordNumber = FormattedRowNumber(account, index + 1),
          CreditRegistryId = account.CreditRegistryId,
          DateLastUpdated = (
                                                from h in context.AccountHistory 
                                                where h.CreditorRegistryId == creditorRegistryId 
                              && h.AccountNo == accountNo 
                                                select h.LastUpdated).Max(),
          AccountNumber = FormattedAccountNumber(account.AccountType, account.AccountNumber)
        })
        .OrderBy(c=>c.FormattedRecordNumber)
        .ThenByDescending(c => c.StateChangeDate);

また、クエリでFormattedAccountNumberやFormattedRecordNumberなどの関数を呼び出していることにも気付きました。これらがデータベースからエンティティデータモデルにインポートして正しくマッピングされたストアドプロシージャまたは関数でない限り、これらも例外をスローします。EFはこれらの関数をデータストアに送信できるステートメントに変換する方法を知らないためです。

また、AsEnumerableを呼び出しても、クエリの実行は強制されません。クエリの実行が列挙されるまで延期されるまで。必要に応じて、ToListまたはToArrayを使用して列挙を強制できます。


必要に応じて、実行中のクエリをリファクタリングして、アカウントレポートクエリの選択プロジェクションに直接DateLastUpdatedを取得し、エラーなしで目的の効果を得ることができます。
ジェームズアレクサンダー

メインクエリ内に関数のコードを配置した後も同じエラーが発生します
DotnetSparrow

2

ラディスラフ・ムルンカの答えに加えて:

[設定 ]タブでコンテナを公開および上書きする場合は、MultipleActiveResultSetをTrueに設定でき ます。このオプションは、[ 詳細... ]をクリックすると表示され、[ 詳細 ] グループの下に表示されます


2

グーグル経由でこれを見つける人のために;
エラーで示唆されているように、同じSqlCommandで別のSqlDataReaderを作成する前にSqlDataReaderを閉じることができなかったため、このエラーが発生しました。

sqlDataReader.Close();2つ目のリーダーを作成する前に電話をかけて問題を解決しました。


2

私の場合、次のようなデータコンテキストからクエリを開きました

    Dim stores = DataContext.Stores _
        .Where(Function(d) filter.Contains(d.code)) _

...その後、同じように照会しました...

    Dim stores = DataContext.Stores _
        .Where(Function(d) filter.Contains(d.code)).ToList

.ToList最初にを追加すると問題が解決しました。これを次のようなプロパティでラップすることは理にかなっていると思います:

Public ReadOnly Property Stores As List(Of Store)
    Get
        If _stores Is Nothing Then
            _stores = DataContext.Stores _
                .Where(Function(d) Filters.Contains(d.code)).ToList
        End If
        Return _stores
    End Get
End Property

_storesはプライベート変数で、FiltersもAppSettingsから読み取る読み取り専用プロパティです。


1

読み取りループ内で一部のレコードを更新しようとしたときに、同じエラーが発生しました。私は最も投票された回答MultipleActiveResultSets=trueを試しましたが、次のエラーを取得するための回避策であることがわかりました 

セッションで他のスレッドが実行されているため、新しいトランザクションは許可されません

巨大なResultSetで機能する最善のアプローチは、チャンクを使用し、エンティティフレームワークからのSqlExceptionで説明されているように、チャンクごとに個別のコンテキストを開く  ことです。セッションで他のスレッドが実行されているため、新しいトランザクションは許可されません


1

私はawait _accountSessionDataModel.SaveChangesAsync();を変更してこの問題を解決しました。_accountSessionDataModel.SaveChanges();に 私のリポジトリクラスで。

 public async Task<Session> CreateSession()
    {
        var session = new Session();

        _accountSessionDataModel.Sessions.Add(session);
        await _accountSessionDataModel.SaveChangesAsync();
     }

それを次のように変更しました:

 public Session CreateSession()
    {
        var session = new Session();

        _accountSessionDataModel.Sessions.Add(session);
        _accountSessionDataModel.SaveChanges();
     }

問題は、セッションを(コードで)作成した後、フロントエンドでセッションを更新したことですが、SaveChangesAsyncは非同期で発生するため、明らかにSaveChangesAsyncオペレーションがまだ準備されていないため、セッションをフェッチするとこのエラーが発生しました。


1

私にとっては、それは自分自身のバグでした。私はINSERTを使用SqlCommand.executeReader()するべきだったときに使用を実行しようとしていましたSqlCommand.ExecuteNonQuery()。開かれ、決して閉じられなかったため、エラーが発生しました。この見落としに注意してください。


私の側からも同じ問題でした。Inserted rows IDを取得しているため、SqlCommand.executeReader()が必要でした。だから:私はSqlDataReader.Close();を使用しました。SQL Command.Dispose(); ありがとう@Andrew Taylor
Fuat

1

これは、実際のシナリオから抽出されます。

  • 接続文字列にMultipleActiveResultSetsが設定されているステージ環境でコードが適切に機能する
  • MultipleActiveResultSets = trueなしで本番環境に公開されたコード
  • 単一のページが失敗している間、多くのページ/呼び出しが機能する
  • 呼び出しを詳しく見ると、dbに対して不要な呼び出しが行われており、削除する必要があります
  • ProductionでMultipleActiveResultSets = trueを設定し、クリーンアップされたコードを発行すると、すべてが効率よく機能します

結論として、MultipleActiveResultSetsを忘れずに、コードが長時間実行されてから、非常にコストがかかる可能性のある冗長なdb呼び出しが見つかる可能性があります。MultipleActiveResultSets属性の設定に完全に依存せず、コードがそれを必要とする理由を見つけることをお勧めしますそれが失敗したところ


1

おそらくこの問題は、Entity Frameworkの「遅延読み込み」機能が原因で発生します。通常、最初のフェッチ中に明示的に要求されない限り、結合されたすべてのデータ(他のデータベーステーブルに格納されているもの)は、必要な場合にのみフェッチされます。多くの場合、それは不必要なデータのフェッチを防ぎ、クエリのパフォーマンスを向上させ(結合なし)、帯域幅を節約するので、良いことです。

質問に記載されている状況では、最初のフェッチが実行され、「選択」フェーズ中に遅延読み込みデータが要求されたときに追加のクエリが発行され、EFが「open DataReader」について不平を言っています。

承認された回答で提案された回避策はこれらのクエリの実行を許可し、実際にリクエスト全体が成功します。

ただし、データベースに送信されたリクエストを調べると、複数のリクエストに気づくでしょう-欠落している(遅延ロードされた)データごとに追加のリクエストがあります。これはパフォーマンスキラーかもしれません。

より良いアプローチは、最初のクエリ中に必要なすべての遅延読み込みデータをプリロードするようにEFに指示することです。これは、 "Include"ステートメントを使用して実行できます。

using System.Data.Entity;

query = query.Include(a => a.LazyLoadedProperty);

このようにして、必要なすべての結合が実行され、必要なすべてのデータが単一のクエリとして返されます。質問に記載されている問題は解決されます。


Includeを使用してEntityEntry.Collection()。Load()を使用するようになり、私の解決策が機能するようになったため、これは有効な回答です。残念ながら、ジェネリックのインクルードは別のジェネリックを「ThenInclude」することはできないため、EntityEntry.Collection()。Load()を機能させようとしています。
AndrewBenjamin

0

ツールでWebサービスを使用していますが、これらのサービスはストアドプロシージャをフェッチします。より多くのクライアントツールがWebサービスをフェッチする一方で、この問題が発生します。これらの関数にSynchronized属性を指定して、ストアドプロシージャをフェッチすることで修正しました。現在は正常に機能しています。エラーがツールに表示されることはありません。

 [MethodImpl(MethodImplOptions.Synchronized)]
 public static List<t> MyDBFunction(string parameter1)
  {
  }

この属性を使用すると、一度に1つの要求を処理できます。これで問題が解決します。


0

補足として...これは、SQLオブジェクトからの(内部)データマッピングに問題がある場合にも発生する可能性があります。

例えば...

私が作成したSQL Scalar Functionその誤っ返さをVARCHAR...そして...で列を生成するためにそれを使用しましたVIEWVIEW正確にマッピングされたDbContextので... LINQのは、うまくそれを呼んでいました。ただし、エンティティはDateTimeを予期しましたか?そしてVIEW帰国した文字列を

奇妙に投げる...

「このコマンドに関連付けられている開いているDataReaderがすでに存在するため、最初に閉じる必要があります」

理解するのは難しかったです...しかし、私がリターンパラメータを修正した後...すべてが順調でした


0

私の場合、接続文字列にを設定するMultipleActiveResultSets必要がありTrueました。
次に、同じデータコンテキストで2つの(SQL)コマンドを同時に実行できないことに関する別のエラー(実際のエラー)が表示されました。(EF Core、コードを最初に)
したがって、私にとっての解決策は、他の非同期コマンドの実行を探してそれらを同期に切り替えることでした。

お役に立てば幸いです

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.