存储库实现

问题描述:

我正在考虑改进我当前的存储库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. 额外的方法和它仍然是单元测试。

请您指点我的方法泄漏或提供您对问题的看法?此外,链接到现有的文章将是伟大的。

我的建议是将您的架构降至最低限度,并向您自己证明每个添加的图层和抽象的好处。最小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项目中使用存储库进行测试。