如何获取DbContext尚未保存的插入记录的可见性
问题描述:
我正在实现一个服务层,我需要确保跨多个表的特定数量的操作发生在事务中。这是工作流程。如何获取DbContext尚未保存的插入记录的可见性
- 我得到一个需要存储在HistoricalData表中的HistoricalData对象的实例。这是在AddHistoricalData方法中完成的。
- 我需要从HistoricalData表中检索所有记录,包括#1中插入的内容,但可以有更多记录。这在ProcessAllData方法中完成。
- 处理所有这些记录后,结果存储在另外两个表中,即ProcessStatus和ProcessResults。如果出现任何问题,我需要回滚事务,包括在操作#1中插入的内容。
这是如何实施的。
public class HistoricalDataService : IHistoricalDataService
{
private MyDbContext dbContext;
public HistoricalDataService(MyDbContext context)
{
this.dbContext = context;
}
void AddHistoricalData(HistoricalData hData)
{
// insert into HistoricalData table
}
void ProcessAllData()
{
// Here we process all records from HistoricalData table insert porcessing results into two other tables
}
void SaveData()
{
this.dbContext.SaveChanges();
}
}
这里是如何调用这个类的方法。
HistoricalDataService service = new HistoricalDataService (dbcontext);
service.AddHistoricalData(HistoricalData instance);
service.ProcessAllData();
service.SaveData();
问题这种方法是,无论是调用AddHistoricalData方法时插入HistoricalData表是不是在ProcessAllData呼叫可见,因为dbContext.SaveChanges只在最后调用。我在想,我需要以某种方式将事务范围引入此处,但不知道如何在应该启动该事务范围的位置公开一个函数?
答
有不同的方法可以做到这一点。试试这个(未经测试,但POC)
public class HistoricalDataService : IHistoricalDataService
{
private DbContext dbContext;
private DbContextTransaction dbContextTransaction;
public HistoricalDataService(DbContext context)
{
this.dbContext = context;
}
void AddHistoricalData(HistoricalData hData)
{
if (dbContext.Database.CurrentTransaction == null)
{
dbContextTransaction = dbContext.Database.BeginTransaction();
}
// insert into HistoricalData table
dbContext.SaveChanges();
}
void ProcessAllData()
{
// Here we process all records from HistoricalData table insert porcessing results into two other tables
}
void Rollback()
{
if (dbContextTransaction != null)
{
this.dbContextTransaction.Rollback();
}
}
void SaveData()
{
this.dbContextTransaction.Commit();
this.dbContextTransaction.Dispose();
}
}
使用这样:
HistoricalDataService service = new HistoricalDataService (dbcontext);
try
{
service.AddHistoricalData(HistoricalData instance);
service.ProcessAllData();
service.SaveData();
}
catch (Exception ex)
{
service.Rollback();
}
答
我建议重构代码,以便服务有一个方法(在更高的抽象水平)和单一责任:处理用例。
那么,客户端类将有
private readonly IHistoricalDataService _historicalDataService;
_historicalDataService.RearrangeSeatingArrangement(); //High level abstraction
上述这样做的目的是为了确保你的服务类有发生一个方法中的所有操作,包裹着要么事务范围内,如果使用原始ADO .NET或上下文对象如果使用EF。当它可以调用ONE时,不要让客户端类调用三种方法。这首先是服务类的目的:处理用例并将响应返回给客户端类(可能是您的控制器)。
现在,当涉及到确保代码的某些部分知道已保存的数据时,它会带来一些其他问题:上面的ProcessAllData()过程中发生的命令,为什么它会精确地分割数据?可以将拆分的数据拆分到内存中(在另一个域类中),添加到上下文并保存在SaveChanges()方法中?这样可以确保您只调用一次数据库(这是实体框架工作单元的目的,即:在上下文中累积更改,添加,删除,更新,然后在一个操作中与数据库交谈)。
你为什么说HistoricalData不可见?如果您将HistoricalData对象插入到dbContext.HistoricalData中,那么您应该能够在ProcessAllData方法中获得此对象 – taquion
不知道为什么,但使用context.HistoricalData插入AddHistoricalData方法的位置。添加仅在Context.HistoricalData集合中的ProcessAllData方法中可见。我的猜测是我必须在上下文中调用SaveChanges –