EF核心DbContext实例生命周期

时间:2019-07-19 09:01:50

标签: c# entity-framework-core

我有一个“已记录”的堆栈,但有一点点更改,我将EFContexts放在接口后面,并且遇到了将所有已知上下文类型注入到ctor中的情况,因此我的DI设置看起来像这样...

services.AddDbContext<MembershipDataContext>(options => options.UseSqlServer(Config.Connections["Membership"]));
services.AddDbContext<CoreDataContext>(options => options.UseSqlServer(Config.Connections["Core"]));
services.AddDbContext<B2BDataContext>(options => options.UseSqlServer(Config.Connections["B2B"]));

services.AddScoped<IMembershipDataContext, MembershipDataContext>();
services.AddScoped<ICoreDataContext, CoreDataContext>();
services.AddScoped<IB2BDataContext, B2BDataContext>();
services.AddScoped<IEnumerable<IDataContext>>(i => new IDataContext[] { i.GetService<MembershipDataContext>(), i.GetService<CoreDataContext>(), i.GetService<B2BDataContext>() });

我的理解是,对于一个HTTP请求,当我在多个地方请求其中的任何一个时,我会得到相同的实例,逻辑是这样的……

A => B => ICoreDataContext 
A => IEnumerable<IDataContext>

...应该给A和B相同的CoreDataContext实例,因此当B从数据库中提取某些实体并且A调用SaveChangesAsync()时,这应该不是问题。

尽管如此,我似乎还是得到了这个例外...

The instance of entity type 'User' cannot be tracked because another instance with the same key value for {'Id'} is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the conflicting key values.

...当我对多个表执行复杂的操作并且父对象(在本示例中为A)尝试调用保存更改时。

是从EF的2个不同父对象中“获取”对象的实例,而是从同一上下文实例中“获取”一个对象的行为吗?

我的代码实际上在做什么...

  • A =>获取ID为1的Foo
  • B =>获得一堆Foo与 可能包含A
  • 中的一个的各种ID
  • B =>对所有内容进行更改 变得愚蠢
  • C =>完成许多不同的B后,C会调用 在所有上下文上保存更改

因为C没有得到任何帮助,这是不允许的吗? 我的理解是,所谓的SaveChanges无关紧要,因为我应该只与我交互的CoreDataContext实例(共享),并且在整个过程中只进行了1次保存调用。

1 个答案:

答案 0 :(得分:-1)

在获取用户并保存用户时是否使用异步操作?如果是这样,您可能正在尝试执行EF Core不支持的并行操作。

https://docs.microsoft.com/en-us/ef/core/miscellaneous/configuring-dbcontext

部分:

  

避免DbContext线程问题

解释您在小节中看到的奇怪行为:

  

忘记在等待异步操作完成之前   在同一DbContext上启动其他任何操作

     

如果无法检测到并发访问,则可能导致未定义   行为,应用程序崩溃和数据损坏。

在您的情况下,当您尝试将A保存到B中时可能尚未完成获取操作(反之亦然)。尝试同步进行操作,看看是否发现相同的问题,我认为您不应该这样做。