这些是我的Web Api设置中的AutoFac-DI定义:
builder.RegisterType<MyContext>().As<MyContext>().InstancePerRequest();
builder.RegisterType<TestRepository>().InstancePerRequest();
builder.RegisterType<SchoolclassCodeRepository>().InstancePerRequest();
builder.RegisterType<TestService>().InstancePerRequest();
TestService构造函数接受TestRepository和SchoolclassCodeRepository。两个存储库都接受MyContext的相同实例。
我同意这个:Is it wise to use same DbContext with multiple repositories?
分享上下文有其他充分的理由,其中一个(恕我直言)是上下文必须跟踪实体的状态,如果你得到一个实体,处理上下文,做一些修改实体,然后附加到新的上下文,这个新的上下文必须到达数据库,以便它可以找出实体的状态。同样,如果您正在处理实体图表(发票及其所有InvoiceItems),则新上下文必须获取图表中的所有实体以确定其状态。
但是现在我用这种架构打了一条单行道!
如果我必须跨多个存储库执行事务该怎么办?
使用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();
}
}
当我现在采取上述示例并尝试对服务中的2个存储库执行相同操作时,我面临严重问题。
如何在不更改我的存储库的情况下在多个存储库上创建事务?
示例我想要的东西:
在我的TestService中,我想粗略地做一下:
public void Save()
{
// Open Transaction
// testRepo.Insert();
// schoolclassCodeRepo.Delete();
// Commit Transaction
}
更新
在我的TestService中,我将所有实体从repos映射到DTO对象,然后在我的web api控制器中通过数据+链接(Rest)进行丰富。
更新2
实现所有Repository方法作为DbContext的扩展方法并不是更好,这样我可以直接在注入TestService的ONE 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;
}
}
}
此代码工作正常!
答案 0 :(得分:3)
您不会更改您的存储库,但您的架构中肯定缺少工作单元。这是您共享多个存储库的单个上下文的位置。
将UoW视为DbContext,其中存储库是DbSets。
UoW uow = new UoW( context );
uow.BeginTransaction();
uow.Repository1.... // query, insert, update, delete
uow.Repository2....
uow.Commit();
典型的实现只暴露了多个存储库:
public class UoW {
public UoW( DbContext ctx ) {
this._ctx = ctx;
}
private Repository1 _repo1;
public Repository1 Repo1
{
get
{
if ( _repo1 == null )
_repo1 = new Repository1( this._ctx );
return _repo1;
}
...
如果你需要一个完整的教程,请看一下:
答案 1 :(得分:1)
您可以使用事务范围而不是dbcontexttransaction执行此操作:
using (var scope = new TransactionScope(TransactionScopeOption.Required,
new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted }))
{
// Your code
scope.Complete();
}
注意在跨数据库使用它时,它将使用MSDTC。