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

时间:2011-03-09 04:37:51

标签: entity-framework entity-framework-4 domain-driven-design repository inversion-of-control

我想我要去看看。

我正在使用EF4& amp; POCO(数据库优先)和IoC。我的存储库和UoW模式大多采用this articlethis article

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

实现:

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

接口:

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

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

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

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

如果不是这种情况,那么如何在服务层中执行复杂查询such as this

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

提前致谢。

2 个答案:

答案 0 :(得分:8)

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

return _repository // IRepository<T>
          .Find() // IQueryable<T>
          .Where(someComplexPredicate) // IQueryable<T>
          .SingleOrDefault(); // T

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

如果您想开始执行ObjectSet<T> - 服务中的特定事项,您有两种选择:

  1. 将特定于ObjectSet<T>的方法公开为Repository接口上的方法
  2. 使用IQueryable<T>扩展程序对ObjectSet<T>进行“软投射”(例如var objSet = source as ObjectSet<T>)。
  3. 始终尝试使用选项1。

    完美的例子是渴望加载。 Include上有一个名为ObjectContext<T>的方法,因此如果您在存储库中使用IQuerayable<T>,那么您如何急切加载?

    由于Include采用“魔术字符串”,您可以在存储库的Find方法中接受此操作,例如:

    return _repository // IRepository<T>
              .Find("Product.Orders") // IQueryable<T>
              .Where(someComplexPredicate) // IQueryable<T>
              .SingleOrDefault(); // T
    

    幸运的是,在EF CTP5中,他们引入了一个强类型Include,它在IQueryable<T>之后工作,所以当我进行切换时,我没有必要执行上述操作。

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

答案 1 :(得分:1)

实体框架本身就是一个存储库。为什么要添加额外的复杂层(存储库)。它只是使查询更加困难,你必须反复编写所有重复代码(FindById(),FindAll(),FindAllByName()....)