web-dev-qa-db-ja.com

エンティティフレームワークの新しいトランザクションは、セッションで実行されている他のスレッドがあるため許可されません。マルチスレッドの保存

マルチスレッドプロセスのログをDBに保存しようとしていますが、次のエラーが発生します。セッションで他のスレッドが実行されているため、新しいトランザクションは許可されません。

各トレッドにこの機能があります:

 internal bool WriteTrace(IResult result, string message, byte type)
    {
        SPC_SENDING_TRACE trace = new SPC_SENDING_TRACE(
                        message,
                        Parent.currentLine.CD_LINE,
                        type,
                        Parent.currentUser.FULLNAME,
                        Parent.guid);
        Context.SPC_SENDING_TRACE.AddObject(trace);
        if (Context.SaveChanges(result) == false)
            return false;
        return true;

    }

コンテキストはスレッドごとに異なりますが、DBとの接続は常に同じです。

この問題を解決する方法はありますか?

ありがとうアンドレア

11
andrea

各トランザクションのコンテキストを作成して破棄する必要があります。これは次のように実行できます。

_using(var ctx = new MyContext()) {
    //do transaction here
}
_

閉じたブラケットの後、コンテキストは破棄されます。

理解を深めるには、 この投稿 を参照してください。 ken2k ですばらしい答えを見つけることができます。あなたがあなたの問題を修正できることを願っています:)

更新:

また、すべてのLINQクエリに.ToList()を追加してみてください。 LINQの結果を反復処理する場合、反復が終了するまで変更を加えることはできません。そのようなものがあるかどうか、またはより多くのコード、つまりWriteTraceを呼び出すコードを共有しているかどうかを確認します。今回はこれが実際にあなたを助けることを願っています。

38
ecampver

私は、マルチスレッド環境でエンティティフレームワークを使用します。この環境では、任意のスレッド、UI、およびバックグラウンド(STAとMTAの両方)が同じデータベースを同時に更新できます。新しいバックグラウンドスレッドでの使用開始時にエンティティ接続を最初から再作成することで、この問題を解決しました。エンティティ接続インスタンスを調べると、ConnectionStringは、一般的な接続インスタンスをリンクするために使用されると私が想定しているリーダーGUIDを示しています。エンティティ接続を最初から再作成することにより、GUID値はスレッドごとに異なり、競合は発生していないように見えます。

// Build the connection string.

  var sqlBuilder = new SqlConnectionStringBuilder();
  sqlBuilder.DataSource = serverName;
  sqlBuilder.InitialCatalog = databaseName;
  sqlBuilder.MultipleActiveResultSets = true;
  ...
  var providerString = sqlBuilder.ToString();
  var sqlConnection = new SqlConnection(providerString);

// Build the emtity connection.

  Assembly metadataAssembly = Assembly.GetExecutingAssembly();
  Assembly[] metadataAssemblies = { metadataAssembly };
  var metadataBase = @"res://*/{0}.csdl|res://*/{0}.ssdl|res://*/{0}.msl";
  var dbModelMetadata = String.Format(metadataBase, objectContextTypeModelName);
  // eg: "res://*/Models.MyDatabaseModel.csdl|res://*/Models.MyDatabaseModel.ssdl|res://*/Models.MyDatabaseModel.msl"
  var modelMetadataPaths = modelMetadata.Split('|');
  var metadataWorkspace = new MetadataWorkspace(modelMetadataPaths, metadataAssemblies);
  var entityDbConnection = new EntityConnection(metadataWorkspace, sqlConnection);
  return entityDbConnection;
0
David Coleman