ASP.NET MVC 5 中使用继承接口与通用存储库模式、UnitOfWork 的方法

Using Method of Inherited Interface with Generic Repository Pattern, UnitOfWork in ASP.NET MVC 5

我的问题就出在这里,


我已经为国家存储库编写了一个接口,我正在使用 UnitOfWork 跟踪通用存储库,我也在使用 ninject 用于 DI

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

实施国家信息库界面,

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

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

ICountryRepository接口中还有一个方法,我也实现了。但是当我需要使用 UnitOfWork 使用该方法时,我不能使用该方法。那就是给 System.NullReferenceException

我试过了,

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

向下转换建议该方法,但 不使用 转换该方法不可访问

已提供其他代码,

实体


基础实体

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

产品实体

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

存储库


界面

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

基本存储库

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;
    }
}

工作单元


界面

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

    void BeginTransaction();

    int Commit();

    Task<int> CommitAsync();

    void Rollback();

    void Dispose(bool disposing);

}

实施的工作单元

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
    *
    *
    *
    */
}

如评论中所述,您正在解析类型 BaseRepository<Country> 的实例,而不是派生的 CountryRepository class,这是您要解析的实例Country.

一种粗略的硬编码解决方案是将您的通用存储库类型替换为自定义类型解析。像这样的东西。您将需要手动将条目添加到词典中。

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];
}

您应该创建自定义存储库方法扩展方法。

因此,如果您的额外方法被称为 GetCountriesByContinent,例如

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

您还应该研究协变与逆变,这可能有助于您首先理解为什么会出现此问题。