4
\$\begingroup\$

I am stuck to define a generic repository with AutoFac IOC container. I am keeping thing very simple and only showing relevant information.

BaseEntity

public abstract class BaseEntity
{
    public int Id { get; set; }
}

IRepository

public interface IRepository<TEntity> where TEntity : BaseEntity
{
    List<TEntity> GetAll();
    void Insert(TEntity entity);
    void Update(TEntity entity);
    void Delete(TEntity entity);
}

IUnitOfWork

public interface IUnitOfWork : IDisposable
{
    int SaveChanges();
    void Dispose(bool disposing);
    IRepository<TEntity> Repository<TEntity>() where TEntity : BaseEntity;
}

IService

public interface IService
{
    IUnitOfWork UnitOfWork { get; }
}

IService<TEntity>

public interface IService<TEntity> : IService where TEntity : BaseEntity
{
    List<TEntity> GetAll();
    TEntity GetById(int id);
    void Add(TEntity entity);
    void Update(TEntity entity);
    void Delete(TEntity entity);
}

UnitOfWork

public class UnitOfWork : IUnitOfWork
{

    private readonly IEntitiesContext _context;
    private bool _disposed;
    private ObjectContext _objectContext;
    private Hashtable _repositories;
    private DbTransaction _transaction;


    public UnitOfWork(IEntitiesContext context)
    {
        _context = context;
    }

    public int SaveChanges()
    {
        return _context.SaveChanges();
    }

    public IRepository<TEntity> Repository<TEntity>() where TEntity : BaseEntity
    {
        if (_repositories == null)
        {
            _repositories = new Hashtable();
        }
        var type = typeof(TEntity).Name;
        if (_repositories.ContainsKey(type))
        {
            return (IRepository<TEntity>)_repositories[type];
        }
        var repositoryType = typeof(EntityRepository<>);
        _repositories.Add(type, Activator.CreateInstance(repositoryType.MakeGenericType(typeof(TEntity)), _context));
        return (IRepository<TEntity>)_repositories[type];
    }
}

Service<TEntity>

public class Service<TEntity> : IService<TEntity> where TEntity : BaseEntity
{
    public IUnitOfWork UnitOfWork { get; private set; }

    public Service(IUnitOfWork unitOfWork)
    {
        UnitOfWork = unitOfWork;
    }

    public List<TEntity> GetAll()
    {
        return UnitOfWork.Repository<TEntity>().GetAll();
    }
}

EntityRepository<TEntity>

public class EntityRepository<TEntity> : IRepository<TEntity> where TEntity : BaseEntity
{
    private readonly IEntitiesContext _context;
    private readonly IDbSet<TEntity> _dbEntitySet;

    public EntityRepository(IEntitiesContext context)
    {
        _context = context;
        _dbEntitySet = _context.Set<TEntity>();
    }

    public List<TEntity> GetAll()
    {
        return _dbEntitySet.ToList();
    }
}

Now these are generic repository, services and unit-of-work. In my presentation I am using IService<T> which will be injected through AutoFac. Now I have 2 concerns:

  1. I am directly using EntityRepository inside UnitOfWork var repositoryType = typeof(EntityRepository<>), which is a problem for me because I am injecting dependencies through IOC.

  2. If I need to use a custom Repository (by inheriting EntityRepository) in future, how can I inject it in my UnitOfWork?

\$\endgroup\$
2
\$\begingroup\$

First, I would caution against using the generic repository + unit of work pattern that was super trendy a few years ago because it has problems not unlike the problems you're facing (along with problems stemming from the fact that EF crosses traditional DAL/Domain/BL boundaries). Simply put, I would not use repositories with EF unless absolutely necessary, and if I had to, I would not use the generic repository pattern.

If you're hell-bent on using this pattern, then you will need to understand the origins of the problem you're facing. Because you have a generic type being returned by your UnitOfWork "factory," you aren't able to instantiate it during your bootstrapping, you are being forced to to instantiate it on-demand at runtime, resolving using the type you're using in your UnitOfWork method call.

If you are okay with using the same repository instance for all of your resolutions, then just make your objects require Repository<SomeType> in your object constructors or properties with public setters, then use RegisterGeneric(). You can see how that is used here. This bypasses the entire "at runtime" requirement.

If you want to maintain the pattern of fetching a repository using a method, then you need to treat your UnitOfWork class as a factory and use dynamic instantation.

\$\endgroup\$

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.