这是我在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)DbContext
和ClassA
中的ClassB
是否都相同?这样可以保证吗?
2)如果ClassA
和ClassB
都具有相同的DbContext
,则SaveChanges
中的ClassB
会影响我在其中添加的EntityX
ClassA
?
3)我应该怎么做才能隔离ClassA
和ClassB
中的更改?
答案 0 :(得分:5)
在
DbContext
和ClassA
中我都拥有相同的ClassB
吗?这样可以保证吗?
数据库上下文被注册为作用域相关性,这意味着在处理单个传入请求期间共享实例。每个请求都将获得其自己的依赖项注入范围,因此,在单个请求内,可以确保获得相同数据库上下文实例。
另一方面,您也可以保证为单独的请求获取单独的数据库上下文。
如果
ClassA
和ClassB
都具有相同的DbContext
,SaveChanges
中的ClassB
是否会影响我在{{ 1}}?
对此的简短答案是肯定的。由于它是单个数据库上下文,因此也可以跟踪一个实体的单一集合。因此,如果您先运行EntityX
却没有ClassA
调用,然后再运行ClassA.Method1
,则后者中的SaveChanges
也将保存第一种方法的更改
尽管这听起来可能有问题,但实际上通常不是:请求通常作为控制器动作的一部分进行处理,因此控制流程非常清晰。因此,没有任何并行处理,只要您在使用完上下文后始终对其进行“清理”(例如,通过调用ClassB.Method2
)就不会有问题。
相反,您也可以利用此优势,在整个请求处理过程中共享事务,而无需您的方法就知道它们是事务的一部分。
我应该怎么做才能隔离
SaveChanges()
和SaveChanges()
中的更改?
考虑您是否真正需要隔离。 ClassA
影响ClassB
的唯一方法是Method2
对未保存的实体进行更改时。而且,如果您这样做了,那么您可能仍会滥用您的实体。通常,方法应完成对实体的工作,而不会留下脏状态。