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
    \$\begingroup\$ Why do you reset these states in Rollback? You should dispose the UoW when it isn't committed. \$\endgroup\$ – Gert Arnold Apr 6 '16 at 20:27
2
\$\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\$
  • \$\begingroup\$ Exactly what I was going to answer! \$\endgroup\$ – almaz Apr 8 '16 at 7:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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