ASP.NET MVC – Reusing Logic in Another Repository

code-reusedependency-injectiondesign-patterns

I have an ASP.NET MVC4 web application, with EntityFramework for data access. In the application I have two repositories as follow (this is only an example not my real code):

public class CustomerRepository
{
     ICustomerContext _db;

     public CustomerRepository(ICustomerContext db)
     {
          _db = db;
     }

     ...

     public void DeactivateCustomer(int customerId)
     {
         var customer = _db.Customers.Single(x => x.CustomerId == customerId);
         customer.IsActive = false;
         _db.SaveChanges();
     }
}

And

public class ItemRepository
{
     IItemContext _db;

     public ItemRepository(IItemContext db)
     {
         _db = db;
     }

     ...

     public void DeactivateItem(int itemId)
     {
         var item = _db.Items.Single(x => x.ItemId == itemId);
         item.IsActive = false;

         // The problem is here
         new CustomerRepository().DeactivateCustomer(item.CustomerId);

         _db.SaveChanges();
     }
}

The ItemRepository wants to use the logic of deactivating the Customer from the CustomerRepository without copying the code, or couple both repositories like the example above.

I also want to make both actions (deactivating the item, and deactivating the customer) execute in one transaction (maybe one call to SaveChanges())

Is there any design pattern that can achieve these requirements?

Best Answer

Probably best way to address this is to use a unit of work pattern, and use a business logic layer to handle these.

public class UnitOfWork : IDisposable
{
    private ICustomerContext customerContext;
    private IItemContext itemContext;

    private CustomerRepository customerRepository;
    private ItemRepository itemRepository;

    public CustomerRepository CustomerRepository
    {
        get
        {

            if (this.CustomerRepository == null)
            {
                this.CustomerRepository = new CustomerRepository (customerContext);
            }
            return CustomerRepository;
        }
    }

    public ItemRepository ItemRepository
    {
        get
        {

            if (this.ItemRepository == null)
            {
                this.ItemRepository = new ItemRepositoryitemContext);
            }
            return ItemRepository;
        }
    }

    public void Save()
    {
        customerContext.SaveChanges();
        itemContext.SaveChanges();
    }

    private bool disposed = false;

    protected virtual void Dispose(bool disposing)
    {
        if (!this.disposed)
        {
            if (disposing)
            {
                context.Dispose();
            }
        }
        this.disposed = true;
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}

Now in your business layer, you could simply.

public class ItemWorker 
{
     public void DeactivateItem(int itemId)
     {
         using (var unitOfWork = new UnitOfWork)
         {
             var item = unitOfWork.ItemRepository.GetItem(itemId); 


             unitOfWork.ItemRepository.DeactivateItem(itemId);
             unitOfWork.CustomerRepository.DeactivateCustomer(item.CustomerId);
             unitOfWork.Save();
         }
     } 
}

Reference