为什么在Dispose()方法中隐式提交工作单元是不好的?

sma*_*man 6 .net datacontext design-patterns unit-of-work linq-to-sql

我编写了一个不暴露公共Commit()方法的UnitOfWork实现.相反,UnitOfWork实现IDisposable并且在Dispose()方法中执行Commit .我没有看到任何直接的问题,但它似乎是非正统的,所以我想知道你们是否可以指出一些不这样做的主要原因,我忽略了.

以下是一些示例代码:

public class DataService
{
    public DataService()
    {
        _db = new MyDataContext();
        _exceptionHandler = new SqlExceptionHandler();
    }
    private readonly MyDataContext _db;
    private readonly SqlExceptionHandler _exceptionHandler;
    public void Add(Product product, Cart cart)
    {
        using(UnitOfWork unitOfWork = new UnitOfWork(_db, ex=>_exceptionHandler.Handle(ex)))
        {
            unitOfWork.Create<CartItem>(new CartItem{CartId = cart.Id, ProductId = product.Id});
            unitOfWork.Update<Product>(x => x.Id == product.Id, product => { product.OrderCount++; });
        }
    }
}


public class UnitOfWork : IDisposable
{
    private readonly DataContext _dataContext;
    private readonly Func<Exception, bool> _handleException;
    private bool _dirty;

    public UnitOfWork(DataContext dataContext, Func<Exception,bool> handleException)
    {
        _dataContext = dataContext;
        _handleException = handleException;
    }

    private Table<T> Table<T>()
        where T: class
    {
        return _dataContext.GetTable<T>();
    }
    private T[] Find<T>(Expression<Func<T,bool>> select)
        where T: class
    {
        return Table<T>().Where(select).ToArray();
    }

    public void Create<T>(T persistentObject)
        where T: class 
    {
        Table<T>().InsertOnSubmit(persistentObject);
        _dirty = true;
    }
    public void Update<T>(Expression<Func<T, bool>> select, Action<T> update)
        where T : class
    {
        var items = Find<T>(select);
        if (items.Length > 0)
        {
            foreach (var target in items) update(target);
            _dirty = true;
        }
    }
    public void Delete<T>(Expression<Func<T, bool>> select)
        where T : class 
    {
        var items = Find<T>(select);
        switch (items.Length)
        {
            case 0: return;
            case 1:
                Table<T>().DeleteOnSubmit(items[0]);
                break;
            default:
                Table<T>().DeleteAllOnSubmit(items);
                break;
        }
        _dirty = true;
    }

    public void Dispose()
    {
        if (_dirty)
        {
            Commit(1);
        }
    }

    private void Commit(int attempt)
    {
            try
            {
                _dataContext.SubmitChanges();
            }
            catch (Exception exception)
            {
                if (attempt == 1 && _handleException != null && _handleException(exception))
                {
                    Commit(2);
                }
                else
                {
                    throw;
                }
            }
    }
}  
Run Code Online (Sandbox Code Playgroud)

jga*_*fin 5

因为未处理的异常将提交事务.一个例外意味着某些事情没有按计划进行=交易不应该提交.

如果在处置之前没有被调用Rollback,Dispose那就更好了Commit.

  • 我认为在一天结束时,您不会是唯一一个阅读代码的人,因此您需要设计代码以显示意图.我认为在你的交易代码之后立即使用"可见"的提交方法,对其他人(以及从现在开始的一周内对你自己)的影响更为明显. (3认同)