0

My Problem is from here,


I have written an Interface for country repository and I am following generic repository with UnitOfWork, I am also using ninject for DI

public interface ICountryRepository : IRepository<Country>
{
    List<Country> GetAll();
}

Implemented country repository interface,

public class CountryRepository : BaseRepository<Country>, ICountryRepository
{
    public CountryRepository(DbContextcontext) : base(context)
    {
    }

    public List<Country> GetAll(){
    // Not implemented
    }
} 

There is a additional method in ICountryRepository interface and I have implemented it too. But when I need that method to use using UnitOfWork, I can't use that method. That is giving System.NullReferenceException

I have tried,

ICountryRepository repository = UnitOfWork.Repository<Country>() as ICountryRepository;
return repository.GetAll();

The downcasting suggest the method but without casting the method is not accessible.

Additional Codes are given,

Entities


Base Entity

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

Product Entity

public class Country : BaseEntity
{
    public string Name { get; set; }
}

Repositories


Interface

public interface IRepository<T>
{
    void Add(T entity);
}

Base Repository

public class BaseRepository<TEntity> : IRepository<TEntity> where TEntity : BaseEntity
{
    protected IDbContext _context;
    private readonly IDbSet<TEntity> _dbEntitySet;
    private bool _disposed;

    public BaseRepository(IDbContext context)
    {
        _context = context;
        _dbEntitySet = _context.Set<TEntity>();
    }

    public void Add(TEntity entity)
    {
        _context.SetAsAdded(entity);
    }

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

    public virtual void Dispose(bool disposing)
    {
        if (!_disposed && disposing)
        {
            _context.Dispose();
        }
        _disposed = true;
    }
}

Unit Of Work


Interface

public interface IUnitOfWork : IDisposable
{
    IRepository<TEntity> Repository<TEntity>() where TEntity : BaseEntity;

    void BeginTransaction();

    int Commit();

    Task<int> CommitAsync();

    void Rollback();

    void Dispose(bool disposing);

}

Unit of work implemented

public class UnitOfWork : IUnitOfWork
{
    private readonly IDbContext _context;
    private bool _disposed;
    private Hashtable _repositories;

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

    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(BaseRepository<>);

        _repositories.Add(type, Activator.CreateInstance(repositoryType.MakeGenericType(typeof(TEntity)), _context));

        return (IRepository<TEntity>)_repositories[type];
    }

   /* Other Implementation
    *
    *
    *
    */
}
Abdur Rahim
  • 410
  • 7
  • 18
  • It's probably in this line: `_context.Set()`. Your're passing `BaseProduct` which is not an entity and then EF cannot create a `DBSet`. `UnitOfWork.Repository`should do fine, but `UnitOfWork.Repository` will not. – smoksnes Dec 05 '16 at 12:44
  • I have edited that, Unfortunately that is not the issue. I am still facing the issue @smoksnes – Abdur Rahim Dec 05 '16 at 12:46
  • Nothing seems to implement `IBaseProductRepository` so your cast will always be null. Also, any particular reason for using `Activator`? There's nothing magic going on. You should be able to use `new BaseRepository(_context)`. – smoksnes Dec 05 '16 at 12:54
  • @smoksnes, I've changed that mistake. And I am using Ninject for Dependency Injection that is doing the magic. But The problem is not still solved. – Abdur Rahim Dec 05 '16 at 13:07
  • Possible duplicate of [What is a NullReferenceException, and how do I fix it?](http://stackoverflow.com/questions/4660142/what-is-a-nullreferenceexception-and-how-do-i-fix-it) – Ant P Dec 05 '16 at 13:10
  • You are resolving an instance of type `BaseRepository`, not an instance of type `CountryRepository`. – Maarten Dec 05 '16 at 13:11
  • @Maarten Any possible solution/ resource ? – Abdur Rahim Dec 05 '16 at 13:24
  • Now you're casting to `ICountryRepository`, but you're creating a `BaseRepository`. So the cast will still result in null. – smoksnes Dec 05 '16 at 13:31
  • `ICountryRepository` is NOT the same thing as `IRepository`. You cannot cast the latter to the former. – DavidG Dec 05 '16 at 13:52

2 Answers2

1

As said in the comment, you are resolving an instance of type BaseRepository<Country>, not your derived CountryRepository class, which is the one you want to resolve in case of a Country.

One crude hard coded solution is to replace your generic-repository-type-to-resolve with a custom-type-to-resolve. Something like this. You will need to manually add entries to the dictionary.

private static readonly Dictionary<Type, Type> s_RepositorySuperTypes = new Dictionary<Type, Type> {
    { typeof(BaseRepository<Country>), typeof(CountryRepository) }
};

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 closedRepositoryType = typeof(BaseRepository<>).MakeGenericType(typeof(TEntity));
    if (s_RepositorySuperTypes.ContainsKey(closedRepositoryType)) {
        closedRepositoryType = s_RepositorySuperTypes[closedRepositoryType];
    }
    _repositories.Add(type, Activator.CreateInstance(closedRepositoryType, _context));

    return (IRepository<TEntity>)_repositories[type];
}
Maarten
  • 21,254
  • 3
  • 44
  • 62
0

You should make your custom repository methods extension methods.

So if your extra method was called GetCountriesByContinent something like

public static class CountryRepository
{
    public static IEnumberable<Country> GetCountriesByContinent(this IRepository<Country> repo, string continent)
    {
        return repo.Where(c => c.Continent == continent);
    }
}

You should also look into covariance vs contravariance which may help you understand why you have this issue in the first place.

garethb
  • 3,615
  • 4
  • 28
  • 49