通用储存库与UnitOfWork与IoC自定义方法

本文关键字:IoC 自定义方法 UnitOfWork 储存库 | 更新日期: 2023-09-27 18:06:47

我有一个通用存储库模式与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();
    }
}

我的仓库实现:

    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的引用转换。

如何解决这个错误?对于自定义存储库,我的实现是否正确?

通用储存库与UnitOfWork与IoC自定义方法

基金会错了。通用存储库应该有一个通用的实体参数。您的"通用"存储库确实具有具有通用参数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层,我看不出有什么理由与这个标准示例不同。除了包含多个存储库的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实现中,上下文没有公开。这就是这个抽象层的目的之一。

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

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

这个类定义可以这样读:

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

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

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

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

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

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