2016-09-20 12 views
2

私は数日間、次のことを今や混乱させてきました。EntityFramework DbContextライフサイクル+ Postgres: "操作は既に進行中です。"

私はMono、EntityFrameworkとRepositoryパターン、UnitOfWork、Postgresを使ってNancyアプリを実行しています。ナンシーはTinyIoCをIoCコンテナとして使用しています。

私はフロントエンドでリクエストを待ち行列に入れて、バックエンドに一度に1つのリクエストが当たるようにするWebアプリケーションを持っています。これはすべて正常に動作します。

しかし、同じバックエンドに接続し、バックエンドに要求をキューイングしないiOSアプリケーションを実行すると、問題が発生します。要求がほぼ同時に発生することがあります。ナンシーのブートストラップでは、

2016-09-20T13:30:16.120057436Z app[web.1]: System.Data.Entity.Core.EntityCommandExecutionException: An error occurred while executing the command definition. See the inner exception for details. ---> System.InvalidOperationException: An operation is already in progress. 
2016-09-20T13:30:16.120104535Z app[web.1]: at Npgsql.NpgsqlConnector.StartUserAction (ConnectorState newState) <0x41ad0150 + 0x00313> in <filename unknown>:0 
2016-09-20T13:30:16.120113254Z app[web.1]: at Npgsql.NpgsqlCommand.ExecuteDbDataReaderInternal (CommandBehavior behavior) <0x41acfe30 + 0x0002f> in <filename unknown>:0 
2016-09-20T13:30:16.120119308Z app[web.1]: at Npgsql.NpgsqlCommand.ExecuteDbDataReader (CommandBehavior behavior) <0x41acfe00 + 0x00013> in <filename unknown>:0 
2016-09-20T13:30:16.120125313Z app[web.1]: at System.Data.Common.DbCommand.ExecuteReader (CommandBehavior behavior) <0x41f1a3c0 + 0x00018> in <filename unknown>:0 
2016-09-20T13:30:16.120131185Z app[web.1]: at (wrapper remoting-invoke-with-check) System.Data.Common.DbCommand:ExecuteReader (System.Data.CommandBehavior) 
2016-09-20T13:30:16.120206045Z app[web.1]: at System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.<Reader>b__c (System.Data.Common.DbCommand t, System.Data.Entity.Infrastructure.Interception.DbCommandInterceptionContext`1 c) <0x41f1ac20 + 0x00027> in <filename unknown>:0 
2016-09-20T13:30:16.120220450Z app[web.1]: at System.Data.Entity.Infrastructure.Interception.InternalDispatcher`1[TInterceptor].Dispatch[TTarget,TInterceptionContext,TResult] (System.Data.Entity.Infrastructure.Interception.TTarget target, System.Func`3 operation, System.Data.Entity.Infrastructure.Interception.TInterceptionContext interceptionContext, System.Action`3 executing, System.Action`3 executed) <0x41b1d3c0 + 0x0010e> in <filename unknown>:0 
2016-09-20T13:30:16.120232740Z app[web.1]: at System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.Reader (System.Data.Common.DbCommand command, System.Data.Entity.Infrastructure.Interception.DbCommandInterceptionContext interceptionContext) <0x41f1a880 + 0x00263> in <filename unknown>:0 
2016-09-20T13:30:16.120267802Z app[web.1]: at System.Data.Entity.Internal.InterceptableDbCommand.ExecuteDbDataReader (CommandBehavior behavior) <0x41f1a3f0 + 0x000e6> in <filename unknown>:0 
2016-09-20T13:30:16.120274613Z app[web.1]: at System.Data.Common.DbCommand.ExecuteReader (CommandBehavior behavior) <0x41f1a3c0 + 0x00018> in <filename unknown>:0 
2016-09-20T13:30:16.120318116Z app[web.1]: at (wrapper remoting-invoke-with-check) System.Data.Common.DbCommand:ExecuteReader (System.Data.CommandBehavior) 
2016-09-20T13:30:16.120326788Z app[web.1]: at System.Data.Entity.Core.EntityClient.Internal.EntityCommandDefinition.ExecuteStoreCommands (System.Data.Entity.Core.EntityClient.EntityCommand entityCommand, CommandBehavior behavior) <0x41f154c0 + 0x00043> in <filename unknown>:0 
2016-09-20T13:30:16.120332587Z app[web.1]: --- End of inner exception stack trace --- 
2016-09-20T13:30:16.120336995Z app[web.1]: at System.Data.Entity.Core.EntityClient.Internal.EntityCommandDefinition.ExecuteStoreCommands (System.Data.Entity.Core.EntityClient.EntityCommand entityCommand, CommandBehavior behavior) <0x41f154c0 + 0x000b3> in <filename unknown>:0 
2016-09-20T13:30:16.120344218Z app[web.1]: at System.Data.Entity.Core.Objects.Internal.ObjectQueryExecutionPlan.Execute[TResultType] (System.Data.Entity.Core.Objects.ObjectContext context, System.Data.Entity.Core.Objects.ObjectParameterCollection parameterValues) <0x41f11e50 + 0x000a4> in <filename unknown>:0 

私はしたいとの依存関係を登録しています::ランダムな間隔で

は、バックエンドは、このエラーを投げて開始し

protected override void ConfigureApplicationContainer (TinyIoCContainer container) 
     { 
      base.ConfigureApplicationContainer (container); 

      Database.SetInitializer<ReflectDbContext> (new NullDatabaseInitializer<ReflectDbContext>()); // add this to allow prevent "The context cannot be used while the model is being created" 

     container.Register<IReflectDbContext, ReflectDbContext>(); 
     container.Register<ReflectUnitOfWork>().AsSingleton(); 

     container.Register<IReflectUserRepository, ReflectUserRepository>(); 
     container.Register<IUserRepository<ReflectUser>, ReflectUserRepository>(); 

     container.Register<IReviewRepository, ReviewRepository>(); 

     container.Register<IReviewSetupRepository, ReviewSetupRepository>(); 

     container.Register<IRepositoryV2<ReflectUserActivityItem>, EntityFrameworkRepository<ReflectUserActivityItem>>(); 

     container.Register<IAuthenticationUnitOfWork<ReflectUser, ReflectUserActivityItem>, ReflectUnitOfWork>(); 

     container.Register<IRepository<ReflectUserActivityItem>, NullRepository<ReflectUserActivityItem>>(); //TODO remove this when port is complete 

     container.Register<IErrorLogger, SimpleLogLogger>(); 
     container.Register<IGeoIpDataProvider, TelizeGeoIpDataProvider>(); 
     container.Register<IRepository<ReviewSetup>, ServiceStackOrmLiteRepository<ReviewSetup>>(); 
     container.Register<IEmailExporter, MailChimpUserEmailDataExporter>(); 
     container.Register<IMailer, SmtpMailer>(); 
     container.Register<IUserManager<ReflectUser>, UserManager<ReflectUser, ReflectUserActivityItem>>(); 
     container.Register<IUserMessageManager<ReflectUser>, UserMessageManager<ReflectUser>>(); 

etc... 

} 

私はこれがマルチであることを感じています2つの別々の要求が物事を爆発させる同じDbContext(または基本的な接続)を使用していることを示しています。

ナンシーブートストラップのConfigureRequestContainerメソッドに依存関係を登録しようとしましたが、これは 'Connection is not open`例外をスローします。

この問題の背後にある理論は、この記事では明確に説明されていますhttp://mehdi.me/ambient-dbcontext-in-ef6/

次は私には不明である:

  • は、私は、これはマルチスレッドの問題であると仮定して修正するのですか?
  • 各リクエストが独自のDbContext /接続を使用するようにするためには、TinyIoC/Nancyを使用してDbContextのライフサイクルを管理するために、物事が衝突しないようにする必要があります。

これは複雑な問題であると私は理解しています。追加情報が必要な場合はお知らせください。

ありがとう:-)。

+1

はい、単一のDbContextが複数のスレッドで使用されている可能性があります。要求ごとに新しいインスタンスとしてコンテナにDbContextを登録します。これにより、新しいインスタンスが解決されるたびに新しいインスタンスが作成されます。 – Evk

+0

DbContextを次のように登録します: 'container.Register ();' TinyIoCドキュメントを正しく理解すると、DbContextとマルチインスタンスが登録され、解決されるたびに新しいインスタンスが生成されます。これは私が現時点でどのように設定したのか、上記の状況を引き起こす原因です。つまり、マルチインスタンスであっても、リクエストごとに新しいインスタンスが保証されるわけではありません。 – Corstiaan

+1

いいえ、デフォルトではシングルトンとしてインターフェイスが登録されるため、毎回同じインスタンスが返されるため、問題が発生します。コンテナを作成します。()。AsMultiInstance()をマルチインスタンスとして登録します。 – Evk

答えて

0

今後も同じエラーが発生する可能性がある人のために、私のコメントを少し拡大していきます。おそらくすでに分かっているように、Entity FrameworkのDbContextはいわゆる「作業単位」パターンに従います。つまり、1つの論理作品(単位)に1つのインスタンスを使用する必要があります。複数の作業単位に同じインスタンスを再利用することは望ましくなく、このような場合には失敗につながることさえあります。 SQL Serverとは異なり、PostgresqlはMARS(Multiple Active Result Sets)をサポートしていないため、同じ接続上で同時に複数のコマンドを実行することはできません。 DbContextの単一インスタンスを複数のスレッドから再利用すると、それらのコマンドを実行するときに同じ基本SQL接続が再利用されるため、上記のエラーが発生します。

コメントに記載されているように、問題を解決する方法は、常に操作ごとにDbContextの新しいインスタンスを作成し、後で破棄します。同じ問題 - これは

container.Register<IReflectDbContext, ReflectDbContext>().AsMultiInstance(); 

そして、あなたが別のクラス(例えば、あなたのReflectUnitOfWorkはシングルトンで、あなたがそこフィールドにDbContextを格納した場合の静磁場\シングルトンインスタンスにDbConextインスタンスを格納したことがないことを確認するとして、それを登録する意味します再び)。

関連する問題