2013-02-27 99 views
3

我正在考慮改進我當前的存儲庫GetAll方法實現,並在下面寫了一個代碼。我試圖在Google上找到這種方法的想法,但沒有成功。所以請查看代碼並幫助我回答以下幾個問題。這裏被簡化例如:存儲庫實現

class Service 
{ 
    public void DoOperation() 
    { 
     // Let's say we need to retrieve users by criteria 
     var items = UnitOfWork 
      .Over<User>() // Get repository of User 
      .GetAll()  // Start querying 

      // If we need simple WHERE then use: 
      .Where(x => x.Email == "[email protected]") 

      // If we need more complex condition then use specification: 
      .Using(new UserNameContains("John")) 

      // Execute: 
      .List(); 
    } 
} 

class UnitOfWork 
{ 
    public Repository<T> Over<T>() 
    { 
     // Get from DI container or injected field 
     return new Repository<T>(); 
    } 
} 

class Repository<T> 
{ 
    public QueryWrapper<T> GetAll() 
    { 
     return new QueryWrapper<T>(Session.QueryOver<T>()); 
    } 
} 

class QueryWrapper<T> 
{ 
    // Query from DB session. Init from constructor. 
    private IQueryOver<T> _query; 

    public QueryWrapper<T> Where(Expression<Func<T, bool>> expression) 
    { 
     _query = _query.Where(expression); 
     return this; 
    } 

    public QueryWrapper<T> Using(Specification<T> spec) 
    { 
     var spec = new TSpec(); 
     _query = spec.Apply(_query); 
     return this; 
    } 

    public IEnumerable<T> List() 
    { 
     return return _query.List(); 
    } 
} 

abstract class Specification<T> 
{ 
    public abstract IQueryOver<T> Apply(IQueryOver<T> query); 
} 

class UserNameContains : Specification<User> 
{ 
    // Init from constructor: 
    private string _name; 

    public override IQueryOver<User> Apply(IQueryOver<User> query) 
    { 
     return /* apply filter condition here */; 
    } 
} 

因此,作爲一個結果,我們得到這樣的好處:

  1. 不再需要創建自定義的回購。單一的通用就夠了。
  2. 自定義規範實現現在與數據層分離並且可測試。
  3. 易於使用的服務。
  4. 我們總是能夠延長QueryWrapper支持像OrderBy
  5. 額外的方法和它仍然是單元測試。

請您指點我的方法泄漏或提供您對問題的看法?此外,鏈接到現有的文章將是偉大的。

回答

1

我的建議是將您的架構降至最低限度,並向您自己證明每個添加的圖層和抽象的好處。最小GETALL實現:

Session.Query<User>(); 

如果您有會被重新使用,你可以將其添加爲擴展方法限制。如果可重用代碼變得明顯,那麼重構擴展方法已經足夠簡單了。即使如此,對於簡單的情況,如果您僅包裝Lambda表達式(如本示例中所示),那麼通常對重構幾乎沒有好處。

public static IQueryable<User> UserNameContains(this IQueryable<User> queryable, string text) 
{ 
    return queryable.Where(u => u.UserNameContains(text)); 
} 

我沒有找到存儲庫模式非常有用,但也可以是組織代碼的合理方法。但我真的不喜歡通用存儲庫模式,因爲它爲每個類規則強制一個存儲庫。如果我使用存儲庫,我喜歡將與根對象(例如Project,ProjectStatus等)相關的查詢分組。此外,在通用存儲庫中提供Get或GetAll方法沒有任何好處,因爲ISession已經提供了這些方法。

至於可測試性,查詢測試總是集成測試,在ASP.NET MVC中我直接測試控制器或任何獨立的查詢方法。我在Windows Forms項目中使用存儲庫進行測試。