2016-09-13 31 views
0

我有一個具有UnitOfWork的通用存儲庫模式,我使用的是IoC。除了存儲庫使用的基本方法之外,我有一些自定義方法。我沒有再次實現整個IRepository方法,而是繼承了GenericRepository類。具有IoC定製方法的UnitOfWork的通用庫

這裏是我的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; 
    } 
} 

這裏是定製庫的例子:

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

事實上,一旦你決定要對DbContext/DbSet頂部的UOW /存儲庫層,我看不出有任何理由這樣做不同於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 - >倉庫 - >服務 - > Presention – ykh

+0

我唯一的問題是,爲什麼我應該沒有自定義存儲庫,而是應用我的自定義方法在服務中。我瞭解服務層的目的是揭示業務邏輯,但是實現存儲庫中所有與存儲庫相關的方法似乎更符合邏輯。 – ykh

+0

因爲這會破壞* generic *儲存庫的目的。它還引入了一個不斷重複的決定:我把什麼放在哪裏?有些方法可能看起來適合存儲庫,有些適用於服務,但總會有一個灰色區域。 –

1

據我所看到的,有可能是您的UserAccountRepository類定義了一個錯誤:

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

那類的定義可以讀這樣的:

類型UserAccountRepository是一個通用型與通用C型論證; UserAccountRepository從具有類型C的泛型參數的泛型類GenericRepository繼承;類型C必須從類CSharpAssignmentContext繼承,並且類型C必須實現接口IUserAccountRepository。

刪除從泛型參數C類型約束IUserAccountRepository和逗號後GenericRepository之後加入它應該做的工作:

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

類定義現在可以讀這樣的: 類型UserAccountRepository是一個泛型類型C型通用參數; UserAccountRepository從具有類型C的泛型參數的泛型類GenericRepository繼承;類型UserAccountRepository必須實現接口IUserAccountRepository。泛型參數類型(Type 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我更新了我的答案,請看看 –