如何获得尚未保存DbContext的插入记录的可见性



我正在实现一个服务层,我需要确保在一个事务中跨多个表执行一定数量的操作。这是工作流程。

  1. 我得到一个需要存储在HistoricalData表中的HistoricalData对象实例。这是在AddHistoricalData方法中完成的
  2. 我需要从HistoricalData表中检索所有记录,这些记录包括在#1中插入的内容,但可以有更多记录。这是在ProcessAllData方法中完成的
  3. 处理完所有这些记录后,结果将存储在另外两个表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)。当客户端类可以只调用一个方法时,不要让它调用三个方法。这就是服务类的首要目的:处理用例并将响应返回到客户端类(在您的情况下可能是控制器)。

现在,当涉及到确保代码的某些部分知道已持久化的数据时,它会带来一些额外的问题:在上面的ProcessAllData()过程中出现的命令,它为什么要精确地分割数据?被分割的数据能否在内存中(在另一个域类中)被分割,添加到上下文中,并保存在SaveChanges()方法中?这将确保你只对数据库进行一次调用(这是实体框架工作单元的目的。也就是说:在上下文中累积更改,添加、删除、udpates,然后在一个操作中,与数据库对话)。

最新更新