[C#.NET][Entity Framework] 实践 DAL 共用方法的交易

上个月,同事问我 DAL 里的 CUD 方法若需要共用,事务要怎么写?

首先,要思考处理数据库的 Data Access Layer 里的 CUD方法,该不该共用?

  •  以使用者案例的角度切入看 DAL,它不应该有机会共用,因为每一个作业流程的数据异动方式不会一样。
  •  设计 DAL 方法时,不应该用 Table 的 CRUD 作为 DAO 的 Method,相信我,那只会让事情变得更复杂而已。
  •  共用 DAL 方法,就得把检查机制放在 DAL 方法。

我的 DAL 是依作业流程设计,比如请假作业,就会对应到请假作业的 DAL,该 DAL 就会提供请假作业的查询、新增、更新、删除等功能

架构如下图:


万一,你检视使用者案例后,发现真的要共用方法,那该怎么办?
开始之前:

  • 在 DAL 里每一个方法里的 DbConnection 应该是独立的私有等级,用完就立即放掉,如果你的 DbConnection 是属于全域变量等级,就要用解构子关闭对象;若是属于静态全域等级,我只能为你念佛超渡。
  • 以下的范例,是使用 ADO.NET Entity Framework 的 DbContext,这跟 ADO.NET 的 DbConnection 是一样的意思
先来看看不好的写法:

在同一个数据库连线里,使用TransactionScope是最无脑,也是最耗资源的,处理不好就会有一大堆的 lock 等着你去处理

public int FLowA()
{
    var result = -1;
    using (var db = new FlowDbContext())//←处理数据用完就关掉
    {
        //.....TODO:处理数据
        result = db.SaveChanges();//←保存数据,db.SaveChanges 具有事务的功能
    }
    return result;
}

FlowB 跟 A一样

当需要合并两个 Flow 最无脑的做法就是用 TransactionScope 包起来

public int CombineFlowAB()
{
    var result = -1;
    using (var scope = new TransactionScope())//←不好的写法,不要学
    {
        var resultA = FLowA();
        var resultB = FLowB();
        result = resultA + resultB;
        scope.Complete();
    }
    return result;
}
改善方法:

首先,把连线对象抽出来变成参数,让 isDispose 决定是否要调用 DbContext.Dispose 方法

public int FLowA(FlowDbContext db = null)//← 首先,把连线对象抽出来变成参数,我要由外面决定事务、关闭
{
    var result = -1;
    var isDispose = false;
    if (db == null)//← 若外面没有传东西进来,我就自己建立连线,并开启 isDispose 旗标
    {
        db = new FlowDbContext();
        isDispose = true;
    }
    try
    {
        //.....TODO:处理数据
        result = db.SaveChanges();//保存数据
        return result;
    }
    finally
    {
        if (isDispose)//← 自己挖的洞自己跳
        {
            db.Dispose();
        }
    }
}

由外部方法调用 DbContext.Database.BeginTransaction

public int CombineFlowAB()
{
    var result = -1;
    using (var db = new FlowDbContext())
    using (var trans = db.Database.BeginTransaction())←声明事务对象,此时SaveChanges就不具有事务机制
    {
        try
        {
            var resultA = FLowA(db);
            var resultB = FLowB(db);
            result = resultA + resultB;
            trans.Commit();
            return result;
        }
        catch (Exception)
        {
            trans.Rollback();
            throw;
        }
    }
}

这样一来 FlowA、B 能拥有自己的事务权杖,也能适时地将事务权杖释放出去

若有谬误,烦请告知,新手发帖请多包涵

2010~2017 C# 第四季

原文:大专栏  [C#.NET][Entity Framework] 实践 DAL 共用方法的交易


猜你喜欢

转载自www.cnblogs.com/chinatrump/p/11458495.html
DAL