使用DDD和IoC实现EF4的存储库

Jer*_*ose 5 domain-driven-design entity-framework repository inversion-of-control entity-framework-4

我想我是在圈子里.

我正在使用EF4和POCO(数据库优先)和IoC开发MVC 3解决方案.我的存储库和UoW模式主要是从本文本文中采用的.

我的解决方案由以下项目组成:

实现:

  • 演示文稿(MVC网站)
  • 域服务(业务层)
  • 域存储库(数据访问)
  • 域上下文(我的EF4 edmx和生成的上下文)
  • 域模型(我的EF4生成的POCO)

接口:

  • 域服务接口(业务层接口)
  • 域存储库接口(数据访问接口)
  • 域上下文接口(生成的EF4上下文的接口)

最后,IoC项目将所有内容联系在一起.

如果您在第一篇文章中注意到,作者提到从域服务中删除对ObjectSet的依赖.我假设这是为了可测试性.但问题是,它阻碍了从域服务执行复杂查询的能力,因为IObjectSet和IEnumerable(由存储库上的大多数方法返回)不存在复杂查询的方法.

这是否意味着我应该在我的存储库中进行复杂的查询?我是否应该放弃类似的方法public T Single(Expression<Func<T, bool>> where)并坚持使用类似的方法public T GetUserById(int id)

如果不是这种情况,那么如何在我的服务层中执行此类复杂查询?

看看上面的解决方案大纲和我遇到的问题,我是朝着正确的方向前进,还是我为自己创造了问题?

提前致谢.

RPM*_*984 8

这是主观的/意见问题,但您可以让您的存储库返回IQueryable<T>,然后您可以在您的服务中执行这样的"复杂查询":

return _repository // IRepository<T>
          .Find() // IQueryable<T>
          .Where(someComplexPredicate) // IQueryable<T>
          .SingleOrDefault(); // T
Run Code Online (Sandbox Code Playgroud)

ObjectSet<T>:IQueryable<T>,这使得这成为可能.

如果您想ObjectSet<T>在服务中开始做特定的事情,您有两个选择:

  1. ObjectSet<T>-specific方法公开为Repository接口上的方法
  2. 使用IQueryable<T>扩展方法对ObjectSet<T>(例如var objSet = source as ObjectSet<T>)进行"软转换" .

总是尝试选择1.

完美的例子是渴望加载.有一个名为方法IncludeObjectContext<T>,因此,如果您使用IQuerayable<T>在你的仓库,你怎么了渴望负荷?

因为Include需要一个"魔术字符串",你可以Find在你的Repository 中的方法中接受这个,例如:

return _repository // IRepository<T>
          .Find("Product.Orders") // IQueryable<T>
          .Where(someComplexPredicate) // IQueryable<T>
          .SingleOrDefault(); // T
Run Code Online (Sandbox Code Playgroud)

幸运的是EF CTP5他们已经推出了一个强类型Include,其工作过IQueryable<T>,所以我没有当我割接做以上.

正如我所说,最好的办法是在Repository接口上公开方法.但需要进行权衡 - 界面应该是服务的"合同"或"定义",而不是关于实施.因此EF特定的事情应该通过扩展方法完成.一般事情可以通过存储库界面完成.