隔离EF Core

时间:2018-10-10 08:07:32

标签: c# asp.net-core dependency-injection entity-framework-core

这是我在ASP.NET Core Startup中添加DbContext服务的方式:

services.AddDbContextPool<AppDbContext>(options =>
            options.UseMySql(Configuration.GetConnectionString("DefaultConnection")));

services.AddScoped<ClassA, ClassA>();
services.AddScoped<ClassB, ClassB>();

ClassA-Method1

_dbContext.EntityX.Add(new EntityX { ... });

var product = ClassB.GetProduct(key);

_dbContext.EntityY.Add(new EntityY { Product = product });

_dbContext.SaveChanges();

ClassB-GetProduct

//Check product if it exists in the database
//Else, get details of the product from a Web API

var newProduct = new Product{ ... }
_dbContext.Products.Add(newProduct );

_dbContext.SaveChanges();

return newProduct;

老实说,我还没有尝试过运行此代码,为了简洁起见,这些代码被(大量)剥离了真实代码。

我的问题是:

1)DbContextClassA中的ClassB是否都相同?这样可以保证吗?

2)如果ClassAClassB都具有相同的DbContext,则SaveChanges中的ClassB会影响我在其中添加的EntityX ClassA

3)我应该怎么做才能隔离ClassAClassB中的更改?

1 个答案:

答案 0 :(得分:5)

  

DbContextClassA中我都拥有相同的ClassB吗?这样可以保证吗?

数据库上下文被注册为作用域相关性,这意味着在处理单个传入请求期间共享实例。每个请求都将获得其自己的依赖项注入范围,因此,在单个请求内,可以确保获得相同数据库上下文实例。

另一方面,您也可以保证为单独的请求获取单独的数据库上下文。

  

如果ClassAClassB都具有相同的DbContextSaveChanges中的ClassB是否会影响我在{{ 1}}?

对此的简短答案是肯定的。由于它是单个数据库上下文,因此也可以跟踪一个实体的单一集合。因此,如果您先运行EntityX却没有ClassA调用,然后再运行ClassA.Method1,则后者中的SaveChanges也将保存第一种方法的更改

尽管这听起来可能有问题,但实际上通常不是:请求通常作为控制器动作的一部分进行处理,因此控制流程非常清晰。因此,没有任何并行处理,只要您在使用完上下文后始终对其进行“清理”(例如,通过调用ClassB.Method2)就不会有问题。

相反,您也可以利用此优势,在整个请求处理过程中共享事务,而无需您的方法就知道它们是事务的一部分。

  

我应该怎么做才能隔离SaveChanges()SaveChanges()中的更改?

考虑您是否真正需要隔离。 ClassA影响ClassB的唯一方法是Method2对未保存的实体进行更改时。而且,如果您这样做了,那么您可能仍会滥用您的实体。通常,方法应完成对实体的工作,而不会留下脏状态。