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

时间:2016-12-30 15:44:37

标签: c# transactions entity-framework-6 dbcontext service-layer

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

  1. 我得到一个需要存储在HistoricalData表中的HistoricalData对象的实例。这是在AddHistoricalData方法中完成的。
  2. 我需要检索来自HistoricalData表的所有记录,其中包括在#1中插入的​​内容但可以包含更多记录。这是在ProcessAllData方法中完成的。
  3. 处理完所有这些记录后,结果将存储在另外两个表中,即ProcessStatus和ProcessResults。如果出现任何问题,我需要回滚事务包括在操作#1中插入的​​内容。
  4. 这就是它的实施方式。

    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仅在结尾处被调用。我在想,我需要以某种方式将事务范围纳入此处,但不确定如何公开应该启动事务范围的函数?

2 个答案:

答案 0 :(得分:2)

有不同的方法可以做到这一点。试试这个(未经测试,但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();
}

答案 1 :(得分:0)

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

然后,客户端类将具有

private readonly IHistoricalDataService _historicalDataService;

_historicalDataService.RearrangeSeatingArrangement(); //High level abstraction

执行上述操作的目的是确保您的服务类在单个方法中进行所有操作,如果使用原始ADO.NET,则使用事务范围包装,如果使用EF,则使用上下文对象包装。当它只能调用ONE时,不要让客户端类调用三个方法。这首先是服务类的目的:处理用例并将响应返回给客户端类(在您的情况下可能是控制器)。

现在,当确保代码的某些部分能够识别已经存在的数据时,它会带来一些额外的问题:上面的ProcessAllData()期间发生的命令,为什么它会精确地分割数据?可以将拆分的数据拆分到内存中(在另一个域类中),添加到上下文中并保存在SaveChanges()方法中吗?这将确保您只对数据库进行一次调用(这是实体框架工作单元的目的。即:在上下文中累积更改,添加,删除,udpates,然后在一个操作中,与数据库通信)。