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

How to get visibility to inserted records where DbContext is not saved yet

我正在实施一个服务层,我需要确保在一个事务中发生跨多个 table 的特定数量的操作。这是工作流程。

  1. 我得到一个需要存储在 HistoricalData 中的 HistoricalData 对象的实例 table。这是在 AddHistoricalData 方法中完成的。
  2. 我需要从 HistoricalData table 中检索所有记录,其中包括 #1 中插入的内容,但可以有更多记录。这是在 ProcessAllData 方法中完成的。
  3. 处理所有这些记录后,结果存储在另外两个 table 中,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();
        }
    }

下面是 class 方法的调用方式。

HistoricalDataService service = new HistoricalDataService (dbcontext);
service.AddHistoricalData(HistoricalData instance);
service.ProcessAllData();
service.SaveData();

此方法的问题在于,在调用 AddHistoricalData 方法期间在 HistoricalData table 中插入的任何内容在 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();
}

我建议重构代码,使服务具有单一方法(在更高的抽象级别)和单一职责:处理用例。

那么,客户 class 会

private readonly IHistoricalDataService _historicalDataService;

_historicalDataService.RearrangeSeatingArrangement(); //High level abstraction

执行上述操作的目的是确保您的服务 class 的所有操作都在一个方法中发生,如果使用原始 ADO.NET 则使用事务范围包装,如果使用原始 ADO.NET 则使用上下文对象包装英孚。不要让客户端 class 在它只能调用一个时调用三个方法。这首先是服务 class 的目的:处理用例和 return 对客户端 class 的响应(在您的情况下可能是控制器)。

现在,当谈到确保您的代码的某些部分知道已持久化的数据时,它会带来一些额外的问题:在上面的 ProcessAllData() 期间发生的命令,为什么它会拆分数据确切地?拆分后的数据能否在内存中拆分(在另一个域 class 中),添加到上下文中,并保存在 SaveChanges() 方法中?这将确保您只对数据库进行一次调用(这是 Entity Framework 工作单元的目的。即:累积上下文中的更改、添加、删除、更新,然后在一次操作中与数据库对话) .