2016-09-13 2 views
0

У меня есть шаблон Generic Repository с UnitOfWork, и я использую IoC. Помимо базовых методов, используемых репозиторием, у меня есть некоторые пользовательские методы. Вместо того, чтобы снова использовать все методы IRepository, я унаследовал от класса GenericRepository.Общий репозиторий с UnitOfWork с пользовательскими методами IoC

Вот моя реализация 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; 
    } 

Вот мое единство 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.

Как решить эту ошибку? Является ли моя реализация правильной для пользовательских репозиториев?

+0

Можете ли вы показать свою подпись класса UserAccountRepository? –

ответ

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

В самом деле, как только вы решите, что вы хотите UOW/Repository слой поверх DbContext/DbSet, я не вижу никаких причин, чтобы сделать это по-другому, чем 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 контекст не отображается. Это одна из целей этого слоя абстракции.

+0

Если вы посмотрите на мой UnityCode , вы можете видеть, что я фактически внедряю службы. Причина, по которой я создал IUserAccountRepository, была предназначена только для пользовательских методов. Когда я реализую службы, вместо использования IGenericRepository, я бы использовал пользовательский репозиторий. В вашей последней части кода вы использовали UoW с сервисом. Что я делаю здесь, применяя еще один уровень абстракции. UoW -> DAL -> Репозиторий -> Сервис -> Представление – ykh

+0

Мой единственный вопрос: почему я не должен иметь собственный репозиторий и вместо этого применять свои собственные методы в службе. Я понимаю, что целью уровня сервиса является раскрытие бизнес-логики, но реализация всех методов, связанных с репозиторием в репозитории, кажется более логичной. – ykh

+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 
+0

Кажется, что я обновил свой вопрос с помощью обходного пути, который работал. Я сейчас обновил этот вопрос. Что я делаю в своем настраиваемом репозитории, так это то, что я наследую от GenericRepository и IUserAccountRepository. Когда я наследую только от общего репозитория, он работает нормально, но как только я наследую от IUserAccountRepository, я получаю ошибку, указанную в вопросе – ykh

+0

@ykh. Я обновил свой ответ, пожалуйста, посмотрите. –