Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DI and repository pattern

Currently, my code is similar to this (shortened just to make a point):

DAL

Repository Interface

public interface IRepository<TEntity, in TKey>
{
    IList<TEntity> GetAll();
    TEntity Get(TKey id);
    TEntity Add(TEntity item);
    TEntity Update(TEntity item);
    bool Remove(TKey id);
}

Base EF repository

public class BaseEFRepository<TEntity, TKey> : IRepository<TEntity, TKey> where TEntity: class, IEntity<TKey> where TKey: struct
{
    protected readonly DbContext _dbContext;

    public BaseRepository()
    {
        _dbContext = new MyDB();
        _dbContext.Configuration.ProxyCreationEnabled = false;
        _dbContext.Configuration.LazyLoadingEnabled = false;
    }

    public virtual TEntity Get(TKey id)
    {
        return _dbContext.Set<TEntity>().Find(id);
    }

    public virtual IList<TEntity> GetAll()
    {
        return _dbContext.Set<TEntity>()
            .ToList();
    }

    public virtual TEntity Add(TEntity item)
    {
        _dbContext.Set<TEntity>().Add(item);
        _dbContext.SaveChanges();
        return item;
    }
    .....
    .....
}

A sample implementation of the base repository

public interface IContactsRepository : IRepository<Contact, long>
{
    Contact GetByEmployeeId(string empId, ContactType type);
    IList<Contact> GetByEmployeeId(string empId);
}

public class ContactsRepository : BaseEFRepository<Contact, long>, IContactsRepository
{
    public Contact GetByEmployeeId(string empId, ContactType type)
    {
        var contact = _dbContext.Set<Contact>()
            .FirstOrDefault(d => d.EmployeeId == empId && d.ContactType == type);

        return contact;
    }

    public IList<Contact> GetByEmployeeId(string empId)
    {
        var contacts = _dbContext.Set<Contact>()
            .Where(d => d.EmployeeId == empId)
            .ToList();

        return contacts;
    }
}

BLL

public class Contacts
{
    public Contact Get(long id)
    {
        IContactsRepository repo = ResolveRepository<IContactsRepository>();
        var contact = repo.Get(id);
        return contact;
    }

    public Contact GetByEmployeeId(string empId, ContactType type)
    {
        IContactsRepository repo = ResolveRepository<IContactsRepository>();         
        return repo.GetByEmployeeId(empId, type);
    }
    .......
    .......
}

Now, everything is fine. I can simply do something like this:

 var _contacts = new Contacts();
 var contact = _contacts.GetByEmployeeId("C1112", ContactType.Emergency);

The confusion started when I read this blog post, the author says that using code like:

IContactsRepository repo = ResolveRepository<IContactsRepository>();  

is a bad technique and it's anti-pattern and one should inject everything at the root of code. I can't see how would I do this with repository pattern. I am consuming this using a WCF. So, how on earth would I inject everything from the first call in WCF? I can't get it. What am I missing here?

One last thing, in this case the WCF is the last layer, and it should be only aware of the layer before it, which is the BLL layer. If I am going to implement anything as the author of that blog suggested, I will make the WCF layer aware of the DAL layer, isn't that bad practice? correct me if I am wrong.

like image 995
Nean Der Thal Avatar asked Mar 13 '23 13:03

Nean Der Thal


2 Answers

You need to use Constructor Injection and then compose your objects in the Composition Root.

When you use Constructor Injection, you inject the dependencies through the constructors, so your classes would look like something like this:

public class BaseRepository
{
    protected readonly DbContext _dbContext;

    //...
    public BaseRepository(DbContext context)
    {
        _dbContext = context;
    }
    //...
}

public class ContactsRepository : BaseEFRepository<Contact, long>, IContactsRepository
{
    //...
    public ContactsRepository(DbContext context)
        :base(context)
    {

    }
    //...
}

public class Contacts
{
    private readonly IContactsRepository m_ContactsRepository;

    public Contacts(IContactsRepository contacts_repository)
    {
        m_ContactsRepository = contacts_repository;
    }

    public Contact Get(long id)
    {
        var contact = m_ContactsRepository.Get(id);
        return contact;
    }
    //...
}

Then in the Composition Root your would compose all your objects together. Optionally via a DI container.

Here is an example of such composition that uses Pure DI:

var context = new MyDB();

context.Configuration.ProxyCreationEnabled = false;

context.Configuration.LazyLoadingEnabled = false;

var contacts = new Contacts(new ContactsRepository(context));

In a WCF application that is hosted in IIS, the Composition Root is a custom ServiceHostFactory. This answer provides more details about how to do that.

like image 135
Yacoub Massad Avatar answered Mar 24 '23 17:03

Yacoub Massad


@Matthew's post should answer your question. However, I would like to mention one thing I noticed in your code in relation to the question. You should not try to manually resolve the dependency but it should be injected by the container. I have modified your code to show this behaviour:

public class Contacts
{
    private IContactsRepository repo;
    public Contacts(IContactsRepository injectedContactsRepository)
    {
        repo = injectedContactsRepository;
    }


    public Contact Get(long id)
    {
        var contact = repo.Get(id);
        return contact;
    }

//and other methods definitions...
}
like image 34
Martin Avatar answered Mar 24 '23 17:03

Martin