我的AutoFac-DI定义如下:
builder.RegisterType<MyContext>().As<MyContext>().InstancePerRequest();
builder.RegisterType<TestRepository>().InstancePerRequest();
builder.RegisterType<SchoolclassCodeRepository>().InstancePerRequest();
builder.RegisterType<TestService>().InstancePerRequest();
TestService构造函数接受TestRepository和SchoolclassCodeRepository。这两个存储库都接受MyContext的相同实例。
我同意这个观点:是否明智地使用具有多个存储库的同一DbContext?
然而,共享上下文还有其他很好的理由之一(在我看来),那就是上下文必须跟踪实体的状态,如果您获取一个实体,释放上下文,对实体进行一些修改,然后将其附加到新的上下文中,那么这个新的上下文必须去访问数据库以便确定实体的状态。同样,如果您使用实体图(发票及其所有发票项目)工作,则新上下文必须获取图中的所有实体以确定它们的状态。
但是,现在我在这种架构中遇到了单行道!
如果我需要执行跨多个存储库的事务怎么办?
使用EF6而不使用存储库可以这样做:
using(NorthwindEntities db = new NorthwindEntities())
{
DbContextTransaction transaction = db.Database.BeginTransaction();
try
{
//insert record 1
Customer obj1 = new Customer();
obj1.CustomerID = "ABCDE";
db.Customers.Add(obj1);
db.SaveChanges();
//insert record 2
Customer obj2 = new Customer();
obj2.CustomerID = "PQRST";
db.Customers.Add(obj2);
db.SaveChanges();
transaction.Commit();
}
catch
{
transaction.Rollback();
}
}
现在,当我尝试使用我的服务中的两个仓库进行相同操作时,我遇到了一个严重的问题。
- 我的服务中没有可用的DbContext。
- DbContext是一个DataProvider/Layer层的关注点,应该保留在仓库内部。
那么,我如何在不改变我的仓库的情况下跨多个仓库创建事务呢?
以下是我想要的示例:
在我的TestService中,我想要大致执行以下操作:
public void Save()
{
// Open Transaction
// testRepo.Insert();
// schoolclassCodeRepo.Delete();
// Commit Transaction
}
更新
在我的TestService中,我将所有实体从仓库映射到DTO对象中,然后在我的Web API控制器中通过数据+链接(Rest)进行增强。
更新2
- 仓储模式可以使数据访问方法可重复使用,这是好的。
- 但是,它使得对多个共享同一DbContext的仓库进行事务处理不可能。
如果将所有Repository方法实现为DbContext的扩展方法,那么我是否可以直接在注入到我的TestService中的一个DbContext上调用“Repo扩展方法”?
更新3 解决方案代码
public async Task<bool> DeleteSchoolyearAsync(int id)
{
using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
try
{
await testRepository.DeleteTestTypes(id);
await schoolyearRepository.DeleteAsync(id);
scope.Complete(); // Rollback is done due to using statement...
return true;
}
catch (System.Exception)
{
return false;
}
}
}
这段代码运行正常!
.SaveChanges()
会在其他线程中引起副作用。” - AronSaveChanges()
现在必须在整个缓存中运行ChangeTracker
,而这个缓存现在是整个数据库,每次调用.SaveChanges()
将持续...哦,我不知道...大约5分钟...除非它不会这样做,因为当另一个线程访问DbContext时,它将崩溃。 - Aron.SaveChanges()
之类的方法时,它会扫描所有实体并将实体与“单元格”进行比较。这非常低效。我的观点是,ChangeTracker会将其加载的所有内容保存在内存中,因此随着时间的推移,服务将把整个数据库加载到“缓存”中,因为释放内存的机制是处理DbContext。 - Aron