1
\$\begingroup\$

I've created the unitofwork class below:

 public class UnitOfWork : IUnitOfWork
  {
    private AppDbContext _context { get; set; }
    private IDbTransaction _transaction { get; set; }
    private ObjectContext _objectContext { get; set; }
    private bool _isDisposed;
    public UnitOfWork(AppDbContext context)
    {
      _context = context;
    }
    public DbSet<T> Set<T>() where T : class
    {
      return _context.Set<T>();
    }
    public DbEntityEntry<T> Entry<T>(T entity) where T : class
    {
      return _context.Entry(entity);
    }
    public void Begin()
    {
      _objectContext = ((IObjectContextAdapter)_context).ObjectContext;

      if (_objectContext.Connection.State != ConnectionState.Open)
      {
        _objectContext.Connection.Open();
        if(_transaction != null)
        {
          _transaction.Dispose();
        }
        _transaction = _objectContext.Connection.BeginTransaction();
      }
    }
    public void AutoDetectChangesEnabled(bool option)
    {
      _context.Configuration.AutoDetectChangesEnabled = option;
    }
    public void LazyLoadingEnabled(bool option)
    {
      _context.Configuration.LazyLoadingEnabled = option;
    }

    public void SaveChanges()
    {
      _context.SaveChanges();
    }
    public Task SaveChangesAsync()
    {
      return _context.SaveChangesAsync();
    }
    public void Commit()
    {
      _transaction.Commit();
    }
    public void Rollback()
    {
      _transaction.Rollback();
      foreach (var entry in _context.ChangeTracker.Entries())
      {
        switch (entry.State)
        {
          case System.Data.Entity.EntityState.Modified:
            entry.State = System.Data.Entity.EntityState.Unchanged;
            break;
          case System.Data.Entity.EntityState.Added:
            entry.State = System.Data.Entity.EntityState.Detached;
            break;
          case System.Data.Entity.EntityState.Deleted:
            entry.State = System.Data.Entity.EntityState.Unchanged;
            break;
        }
      }
    }
    public void Dispose()
    {
      if (!_isDisposed)
      {
        if (_context != null)
        {
          _context.Database.Connection.Close();
          _context.Dispose();
          _context = null;
        }
        if(_transaction != null)
        {
          _transaction.Dispose();
          _transaction = null;
        }
        _isDisposed = true;
      }
    }
  }
}

usage

without transaction

_unitOfWork.Set<User>().Add(MyModel);

with transaction

_unitOfWork.Begin();
try {
   _unitOfWork.Set<User>().Add(MyModel);
   _unitOfWork.SaveChanges();
   _unitOfWork.Commit();
}
catch {
   _unitOfWork.Rollback();
}

I must close the transaction in dispose? How can I improve this code?

Observation: I'm use DI with IUnitOfWork, use AutoFac

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Why do you reset these states in Rollback? You should dispose the UoW when it isn't committed. \$\endgroup\$ Commented Apr 6, 2016 at 20:27

1 Answer 1

3
\$\begingroup\$

Ef already implements unit of work in itself, as does it the repository pattern.

Since you open the connection yourself I take it you use EF6, which also automatically wraps SaveChanges in a transaction if there isn't one already, so you have little use of your UnitOfWork.

Read more at Microsoft.

If you DO need to open a transaction manually, and you don't care to use the TransactionScope class, the transaction must be opened before the connection opens and should be disposed before you close the connection again.

\$\endgroup\$
2
  • \$\begingroup\$ Exactly what I was going to answer! \$\endgroup\$
    – almaz
    Commented Apr 8, 2016 at 7:48
  • \$\begingroup\$ The best evidence that EF already implements UoW is the fact, that OP's code just delegates all operations straight to the context. \$\endgroup\$
    – t3chb0t
    Commented Aug 22, 2019 at 19:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.