首页 新闻 会员 周边

Should I returning IQueryable<T> from a repository?

0
悬赏园豆:100 [已解决问题] 解决于 2017-03-30 13:38

在DDD 的 Repository 层的设计中,是否应该返回 IQueryable<T> 类型,或者返回其他类型?为什么?
问题来源:刚刚在看 规约模式时,看了一篇文章,他是这样写的。


Returning IQueryable from a repository
A question that is somewhat related to the specification pattern is: can repositories just return an IQueryable? Wouldn’t it be easier to allow clients to query data from the backing store the way they want? For example, we could add a method to the repository like this:

// Repository
public IQueryable<T> Find()
{
    return session.Query<T>();
}

And then use it in a controller specifying the actual criteria ad hoc:

// Controller
public void SomeMethod()
{
    List<Movie> movies = _repository.Find()
        .Where(movie => movie.MpaaRating == MpaaRating.G)
        .ToList();
}

This approach has essentially the same drawback as our initial specification pattern implementation: it encourages us to violate the DRY principle by duplicating the domain knowledge. This technique doesn’t offer us anything in terms of consolidating it in a single place.

The second drawback here is that we are getting database notions leaking out of repositories. The implementation of IQueryable highly depends on what LINQ provider is used behind the scene, so the client code should be aware that there potentially are queries which can’t be compiled into SQL.

And finally, we are also getting a potential LSP violation. IQueryables are evaluated lazily, so we need to keep the underlying connection opened during the whole business transaction. Otherwise, the method will blow up with an exception. By the way, an implementation with IEnumerables have essentially the same problem, so the best way to overcome this issue is to return IReadOnlyList or IReadOnlyCollection interfaces.


< >
分享
最佳答案
0

我下面贴两张截图,这是我在Stackoverflow 上收到的答案。供大家参考

1、

2、




BUTTERAPPLE | 老鸟四级 |园豆:3190 | 2017-02-12 17:53
其他回答(3)
-1

这种方法一般是公共方法,针对所有实体都可以调用的,调用时只需把T换成对应的实体即可,这样最方便,不然你写一个实体的查找就得单独写一个方法。

龙行天涯 | 园豆:1794 (小虾三级) | 2017-02-09 16:55
-1

shouldn't

terry59599s | 园豆:202 (菜鸟二级) | 2017-02-17 15:46
1

不是已经写的很清楚了么 

我个人的理解是 数据层 不应该把相关数据层的东西放到另外一层处理

那么就不应该公布 IQueryable 接口

而且 IQueryable 说白了 实际上是一个没有执行的sql语句,提供IQueryable 的好处在于延时加载,坏处在于 其他层级可以修改查询语句(这显然是不合理的)

另外一件事就是 在ef中 IQueryable 实际上意义并非单纯的查询语句那么简单

同时还有对象状态的跟踪 而这一部分知识 上层开发人员其实是不需要知道的 也不是必须技能

如果将 IQueryable 公布在外部 而使用的人 并不知道 IQueryable 的一些规约(对使用IQueryable的人有要求)  会带来一些麻烦 

 

总的来书 不要公布IQueryable 接口给外部

 

但是作为 dal层的内部方法 我是建议使用 IQueryable ,IQueryable 是一个还未执行的sql语句,可以在这个基础之上继续调整查询 直到满意才输出结果 这点显然对写dal的开发是有好处的。

ps:我的意思是 private  和 protect 的方法可以用 IQueryable,但是public 的方法不要用IQueryable

收获园豆:100
小眼睛老鼠 | 园豆:2731 (老鸟四级) | 2017-03-07 14:36

我也是,虽然不推荐。但是还是一直使用IQueryable 返回的数据后,再进行筛选。

支持(0) 反对(0) BUTTERAPPLE | 园豆:3190 (老鸟四级) | 2017-03-07 14:39

@BUTTERAPPLE: 

IQueryable 最大的问题 是会破坏封装 

本来查询数据库是 dal层的事情

如果将IQueryable 公布到外面以后 这就意味着 只要能够接收IQueryable 的位置 都有能力去 调整查询语句

支持(0) 反对(0) 小眼睛老鼠 | 园豆:2731 (老鸟四级) | 2017-03-30 17:36

@小眼睛老鼠: 很多时候都是接受了IQueryable 之后,又去调整。好尴尬(😅)!

支持(0) 反对(0) BUTTERAPPLE | 园豆:3190 (老鸟四级) | 2017-03-30 17:43

@BUTTERAPPLE: 这方面 如果是不同的数据动作 dal层可以多加几个方法

或者将 参数的 lambda 表达式公布出去 这样可以通用化

 

我个人的理念 是不建议将IQueryable 公布出去的 (以前被坑过)

支持(0) 反对(0) 小眼睛老鼠 | 园豆:2731 (老鸟四级) | 2017-03-30 17:50

@BUTTERAPPLE:

这方面多人协作的时候 会体现出来 公布的东西越多 使用的人如果理解不了 

就越容易出问题 所以尽可能少的将一些功能公布到外部 这样也容易控制些

支持(0) 反对(0) 小眼睛老鼠 | 园豆:2731 (老鸟四级) | 2017-03-30 17:52

@BUTTERAPPLE: 有些时候 是有两难的问题

支持(0) 反对(0) 小眼睛老鼠 | 园豆:2731 (老鸟四级) | 2017-03-30 17:59

@小眼睛老鼠: 是的,这确实。正如你所说的,最好还是在Repository中一次把需要的东西查出来。有不同的数据操作,就多加几个方法。

支持(0) 反对(0) BUTTERAPPLE | 园豆:3190 (老鸟四级) | 2017-03-30 18:01
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册