我想我要去看看。
我正在使用EF4& amp; POCO(数据库优先)和IoC。我的存储库和UoW模式大多采用this article和this article。
我的解决方案由以下项目组成:
实现:
接口:
最后,IoC项目将所有内容联系在一起。
如果您在第一篇文章中注意到,作者提到从域服务中删除对ObjectSet的依赖。我假设这是为了可测试性。但问题是,它阻碍了从域服务执行复杂查询的能力,因为IObjectSet和IEnumerable(由存储库上的大多数方法返回)不会存在复杂查询的方法。
这是否意味着我应该在我的存储库中进行复杂的查询?我是否应该放弃像public T Single(Expression<Func<T, bool>> where)
这样的方法,并坚持使用public T GetUserById(int id)
等方法?
如果不是这种情况,那么如何在服务层中执行复杂查询such as this?
看看上面的解决方案大纲和我的问题,我是朝着正确的方向前进,还是我为自己制造问题?
提前致谢。
答案 0 :(得分:8)
这是主观/意见问题,但您可以让您的存储库返回IQueryable<T>
,然后您可以在服务中执行“复杂查询”,如下所示:
return _repository // IRepository<T>
.Find() // IQueryable<T>
.Where(someComplexPredicate) // IQueryable<T>
.SingleOrDefault(); // T
ObjectSet<T>
:IQueryable<T>
,这使得这成为可能。
如果您想开始执行ObjectSet<T>
- 服务中的特定事项,您有两种选择:
ObjectSet<T>
的方法公开为Repository接口上的方法IQueryable<T>
扩展程序对ObjectSet<T>
进行“软投射”(例如var objSet = source as ObjectSet<T>
)。始终尝试使用选项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()....)