1
\$\begingroup\$

I am using WPF with Entity Framework 6 (DB first), Caliburn.Micro, and MEF.

I am trying to implement IoC in my project. I am an absolute beginner in IoC, and unfortunately, I cant find too many examples where MEF is used with Repository Pattern. Here is what I have till now:

All the generated entities inherit this interface:

interface IHasPKey<T>
{        
    T ID { get; }
}

where ID is the Primary Key of the Entity.

Now I have created a GenericRepository like:

class GenericRepository<T> : IRepository<T> where T : class, IHasPKey<Type>
{
    protected readonly DbContext _ctx;

    public GenericRepository(DbContext context)
    {
        _ctx = context;
    }

    virtual public void Add(IEnumerable<T> entitylist)
    {
        _ctx.Set<T>().AddRange(entitylist);
    }

    virtual public void Add(T entity)
    {
        _ctx.Set<T>().Add(entity);
    }

    virtual public void Delete(IEnumerable<T> entitylist)
    {
        foreach (var entity in entitylist)
        {
            var entry = _ctx.Entry(entity);

            if (entry.State == EntityState.Detached)
            {
                _ctx.Set<T>().Attach(entity);
            }
        }
        _ctx.Set<T>().RemoveRange(entitylist);
    }

    virtual public void Delete(T entity)
    {            
        var entry = _ctx.Entry(entity);

        if (entry.State == EntityState.Detached)
        {
            _ctx.Set<T>().Attach(entity);
        }             

        _ctx.Set<T>().Remove(entity);
    }


    virtual public IEnumerable<T> FetchAll()
    {
        return _ctx.Set<T>().ToList();
    }

    virtual public T FetchByPrimaryKey(Type primarykey)
    {
        return _ctx.Set<T>().AsNoTracking.SingleOrDefault(c => c.ID == primarykey);
    }        

    virtual public IEnumerable<T> FindWhere(Expression<Func<T, Boolean>> predicate)
    {
        return _ctx.Set<T>().Where(predicate).AsNoTracking().ToList();
    }

    virtual public T FirstOrDefault(Expression<Func<T, Boolean>> predicate)
    {
        return _ctx.Set<T>().Where(predicate).AsNoTracking().FirstOrDefault();
    }

    virtual public void Update(T updatedentity)
    {
        _ctx.Set<T>().Attach(updatedentity);
        _ctx.Entry(updatedentity).State = EntityState.Modified;
    }

}

and my actual implementation of Repository is like this:

class RateRepository : GenericRepository<Rate>, IRateRepository
{
    public RateRepository(DbContext _ctx) : base(_ctx)
    {
    }

    public BISDContext BISDContext
    {
        get
        {
            return _ctx as BISDContext;
        }
    }

    public IEnumerable<Rate> GetRatesForClient(string clientname)
    {
        return BISDContext.Rates.Where(c => c.Client.ID.Contains(clientname)).ToList();
    }

    public IEnumerable<Rate> GetRatesByItem(string itemname)
    {
        return BISDContext.Rates.Where(c => c.Item.ID.Contains(itemname)).ToList();
    }

    public IEnumerable<ItemLine> GetInvoiceItemsForClient(Client client)
    {            
        return BISDContext.Rates.Where(c => c.Client.ID == client.ID)
                                .OrderBy(c => c.Item.priority)
                                .Select((c) => new ItemLine()
                                {
                                    ThisItem = c.Item,
                                    ItemName = c.Item.ID,
                                    Batch = c.Item.batch,
                                    MRP = (decimal)c.Item.mrp,
                                    Rate = (decimal)c.rate,
                                    Unit = c.Item.displayunit,
                                    Qty = 0,
                                    IsEnabled = true
                                });
    }
}

So far, so good, at least, I hope so.

Now for Unit of Work, I have a GenericUoW:

class GenericUoW : IUoW, IDisposable
{
    protected readonly DbContext _ctx;

    public GenericUoW(DbContext context)
    {
        _ctx = context;
    }

    public void Complete()
    {
        _ctx.SaveChanges();
    }

    public void Dispose()
    {
        _ctx.Dispose();
    }
}

and for actual implementations, I have something like this:

class InvoiceUoW : GenericUoW, IInvoiceUoW
{
    public InvoiceUoW(DbContext _ctx) : base(_ctx)
    {
        salesrepo = new SaleRepository(_ctx);
        itemsrepo = new ItemRepository(_ctx);
        materialrepo = new MaterialRepository(_ctx);
        raterepo = new RateRepository(_ctx);
        clientrepo = new ClientRepository(_ctx);
        taxrepo = new TaxRepository(_ctx);
        stockhistoryrepo = new StockHistoryRepository(_ctx);
        proformarepo = new ProformaRepository(_ctx);
    }

    public ISaleRepository salesrepo { get; private set; }
    public IItemRepository itemsrepo { get; private set; }
    public IMaterialRepository materialrepo { get; private set; }
    public IRateRepository raterepo { get; private set; }
    public IClientRepository clientrepo { get; private set; }
    public ITaxRepository taxrepo { get; private set; }
    public IStockHistoryRepository stockhistoryrepo { get; private set; }
    public IProformaRepository proformarepo { get; private set; }
}

Now, in my ViewModel, I am doing something like this:

[Export(typeof(InvoiceViewModel))]    
class InvoiceViewModel : PropertyChangedBase
{

    #region ctor
    [ImportingConstructor]
    public InvoiceViewModel(IInvoiceUoW invoiceUoW)
    {
        _uow = invoiceUoW;
        Clients = new BindableCollection<Client>(_uow.clientrepo.FetchAll());
    }

    #endregion

    private readonly IInvoiceUoW _uow;

    //other properties and methods
}

Now, the problem is that, in order to keep all the classes testable, I have to keep maintain a huge load of interfaces, one for each repository and one for each Unit of Work. Is this a code smell? Am I overdoing something?

And my second question is related to the use of IoC/DI in InvoiceIoW. How do I implement constructor injection in that class? Because each of those repositories in that class has to be instantiated with the same DataContext.

\$\endgroup\$
  • 1
    \$\begingroup\$ The easiest answer is: inject your repositories into the unit of work and then configure your DbContext lifetime to be what you need it to be. E.g. once per object graph would probably work. The longer answer is that EF already uses the UoW and Repository patterns which makes reinventing it yourself a little pointless :) \$\endgroup\$ – RobH Mar 28 '17 at 7:36
  • \$\begingroup\$ The reason I am using UoW and Repository pattern is because I dont want to expose IQueryable in my viewmodels. \$\endgroup\$ – Sabyasachi Mukherjee Mar 28 '17 at 9:11
  • \$\begingroup\$ how can I get all the repositories in a UoW to be instantiated with the same DbContext? When I try to do constructor injection with MEF, like this public InvoiceUoW(DbContext _ctx, ISaleRepository salerepo, IItemRepository itemsrepo,IMaterialRepository materialrepo, ... ) : base(_ctx), it does something equivalent to this: salesrepo = new SaleRepository(new DbContext()); itemsrepo = new ItemRepository(new DbContext()); materialrepo = new MaterialRepository(new DbContext());... \$\endgroup\$ – Sabyasachi Mukherjee Mar 28 '17 at 11:42

Your Answer

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

Browse other questions tagged or ask your own question.