使用带有IoC自定义方法的UnitOfWork的通用存储库

时间:2016-09-13 00:10:52

标签: c# asp.net-mvc entity-framework repository-pattern

我有一个使用UnitOfWork的通用存储库模式,我正在使用IoC。除了存储库使用的基本方法之外,我还有一些自定义方法。我没有再次实现整个IRepository方法,而是继承了GenericRepository类。

这是我的UnitofWork实施:

public interface IUnitOfWork<T> : IDisposable where T : DbContext
{
    int Save();
    T Context { get; }
}

public class UnitOfWork<T> : IUnitOfWork<T> where T : MyContext, new()
{
    private readonly T _context;

    public UnitOfWork()
    {
        _context = new T();
    }

    public UnitOfWork(T Context)
    {
        _context = Context;
    }

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


    public T Context
    {
        get
        {
            return _context;
        }
    }

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

这是我的Repository实现:

    public interface IGenericRepository
{
    IQueryable<T> All<T>() where T : class;
    void Remove<T>(int id)where T : class;
    void Remove<T>(T entity) where T : class;
    void RemoveRange<T>(IList<T> entities) where T : class;
    T Find<T>(int id) where T : class;
    void Add<T>(T entity) where T : class;
    void AddRange<T>(IList<T> entities) where T : class;
    void Update<T>(T entity) where T : class;
    int SaveChanges();
}

  public class GenericRepository<C> : IGenericRepository where C : MyContext
{
    protected readonly C _context;

    public GenericRepository(IUnitOfWork<C> unitOfWork)
    {
        _context = unitOfWork.Context;
    }

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

    public IQueryable<T> All<T>() where T : class
    {
        return _context.Set<T>();
    }

    public void Remove<T>(int id) where T : class
    {
        T entity = _context.Set<T>().Find(id);
        if (entity != null)
        {
            _context.Set<T>().Remove(entity);
        }
    }

    public void Remove<T>(T entity) where T : class
    {
        if (entity != null)
        {
            _context.Set<T>().Remove(entity);
        }
    }

    public void RemoveRange<T>(IList<T> entities) where T : class
    {
        if (entities.Count > 0)
        {
            _context.Set<T>().RemoveRange(entities);
        }
    }

    public T Find<T>(int id) where T : class
    {
        return _context.Set<T>().Find(id);
    }

    public void Add<T>(T entity) where T : class
    {
        _context.Set<T>().Add(entity);
    }

    public void AddRange<T>(IList<T> entities) where T : class
    {
        _context.Set<T>().AddRange(entities);
    }

    public void Update<T>(T entity) where T : class
    {
        _context.Set<T>().Attach(entity);
        _context.Entry(entity).State = System.Data.Entity.EntityState.Modified;
    }
}

以下是Custom-Repository的示例:

public interface IUserAccountRepository : IGenericRepository
{
    UserAccount Find(string email, string password);
    bool CheckDuplicate(string email);
}

 public class UserAccountRepository<C> : GenericRepository<C> where C : CSharpAssigmentContext, IUserAccountRepository
{
    protected readonly C _context;

    public UserAccountRepository(IUnitOfWork<C> unitOfWork)
    {
        _context = unitOfWork.Context;
    }

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

    /// <summary>
    /// Find user by email and password
    /// </summary>
    public UserAccount Find(string email, string password)
    {
        return _context.Set<UserAccount>().Where(ua => ua.Email == email && ua.Password == password).FirstOrDefault(null);
    }

    /// <summary>
    /// Check wether user exists or not
    /// </summary>
    public bool CheckDuplicate(string email)
    {
        return _context.Set<UserAccount>().Any(ua => ua.Email == email);
    }

    public IQueryable<T> All<T>() where T : class
    {
        return _context.Set<T>();
    }

    public void Remove<T>(int id) where T : class
    {
        T entity = _context.Set<T>().Find(id);
        if (entity != null)
        {
            _context.Set<T>().Remove(entity);
        }
    }

    public void Remove<T>(T entity) where T : class
    {
        if (entity != null)
        {
            _context.Set<T>().Remove(entity);
        }
    }

    public void RemoveRange<T>(IList<T> entities) where T : class
    {
        if (entities.Count > 0)
        {
            _context.Set<T>().RemoveRange(entities);
        }
    }

    public T Find<T>(int id) where T : class
    {
        return _context.Set<T>().Find(id);
    }

    public void Add<T>(T entity) where T : class
    {
        _context.Set<T>().Add(entity);
    }

    public void AddRange<T>(IList<T> entities) where T : class
    {
        _context.Set<T>().AddRange(entities);
    }

    public void Update<T>(T entity) where T : class
    {
        _context.Set<T>().Attach(entity);
        _context.Entry(entity).State = System.Data.Entity.EntityState.Modified;
    }

这是我的Unity IoC代码:

    public static class UnityConfig
{
    public static void RegisterComponents()
    {
        var container = new UnityContainer();

        //UnitOfWork and GenericRepository
        container.RegisterType(typeof(IUnitOfWork<CSharpAssigmentContext>),typeof(UnitOfWork<CSharpAssigmentContext>), new HierarchicalLifetimeManager());
        container.RegisterType(typeof(IGenericRepository), typeof(GenericRepository<CSharpAssigmentContext>), new HierarchicalLifetimeManager());

        //I keep receiving compile ERROR here
        container.RegisterType(typeof(IUserAccountRepository), typeof(UserAccountRepository<CSharpAssigmentContext>), new HierarchicalLifetimeManager());

        //Services
        container.RegisterType(typeof(IUsersAccountsService), typeof(UsersAccountsService), new TransientLifetimeManager());

        DependencyResolver.SetResolver(new UnityDependencyResolver(container));
    }
}

如代码中所述,我不断收到以下代码的编译时错误:

container.RegisterType(typeof(IUserAccountRepository), typeof(UserAccountRepository<CSharpAssigmentContext>), new HierarchicalLifetimeManager());

错误是:

  

MyContext类型不能用作泛型类型或方法中的类型参数C.从MyContext到IMyClassRepository没有任何牵连的引用转换。

如何解决此错误?我的实现是否适用于自定义存储库?

2 个答案:

答案 0 :(得分:1)

据我所知,您的UserAccountRepository类定义可能存在错误:

public class UserAccountRepository<C> : GenericRepository<C>
    where C : CSharpAssigmentContext, IUserAccountRepository

该类定义可以这样解读:

类型UserAccountRepository是泛型类型,其泛型参数类型为C; UserAccountRepository继承自泛型类GenericRepository,其泛型参数类型为C;类型C必须从类CSharpAssignmentContext继承,类型C必须实现接口IUserAccountRepository。

从泛型参数IUserAccountRepository的类型约束中删除C,并在逗号后面的GenericRepository之后添加它应该可以完成这项工作:

public class UserAccountRepository<C> : GenericRepository<C>, IUserAccountRepository
    where C : CSharpAssigmentContext

类定义现在可以这样读: 类型UserAccountRepository是泛型类型,其泛型参数类型为C; UserAccountRepository继承自泛型类GenericRepository,其泛型参数类型为C;类型UserAccountRepository必须实现接口IUserAccountRepository。通用参数类型(类型C)必须从类CSharpAssignmentContext继承。

当你从泛型类/接口继承一个类和其他接口时,你必须首先指定你继承或实现的类型,然后才指定泛型类型约束:

public class SomeImplementation<T1, T2> : ISomeInterface<T1>, IAnotherInterface<T2>, IDisposable, ICloneable 
    where T1 : IAbstraction
    where T2 : class

答案 1 :(得分:1)

基础是错误的。通用存储库应具有通用实体参数。您的“通用”存储库确实具有通用参数T的方法,但无法保证始终使用相同的实体。这就是界面应该是这样的:

public interface IGenericRepository<TEntity> where TEntity : class
{
    IQueryable<TEntity> All();
    void Remove(int id);
    void Remove(TEntity entity);
    void RemoveRange(IList<TEntity> entities);
    TEntity Find(int id);
    void Add(TEntity entity);
    void AddRange(IList<TEntity> entities);
    void Update(TEntity entity);
    int SaveChanges();
}

事实上,一旦您决定在DbContext/DbSet之上想要一个UoW / Repository图层,我认为没有任何理由与this standard example不同。除了包含多个存储库的UoW之外,您还会看到类似的通用存储库。

完成此操作后,您所谓的“UserAccountRepository”应该是包含 UoW的服务,可以由您的IoC容器注入:

public interface IUserAccountService // No repository!
{
    UserAccount Find(string email, string password);
    bool CheckDuplicate(string email);
}

示例实施:

public class UserAccountService : IUserAccountService
{
    private readonly IUnitOfWork<CSharpAssigmentContext> _unitOfWork;

    public UserAccountService(IUnitOfWork<CSharpAssigmentContext> unitOfWork)
    {
        this._unitOfWork = unitOfWork;
    }

您会看到,在此UoW / Repository实现中,不会公开上下文。这是这个抽象层的目的之一。