【发布时间】:2011-10-04 09:33:10
【问题描述】:
我知道以前有人问过这些问题,我将首先列出其中的几个(目前我读过的):
- IEnumerable vs IQueryable
- List, IList, IEnumerable, IQueryable, ICollection, which is most flexible return type?
- Returning IEnumerable<T> vs. IQueryable<T>
- IEnumerable<T> as return type
- https://stackoverflow.com/questions/2712253/ienumerable-and-iqueryable
- Views with business logic vs code
- WPF IEnumerable<T> vs IQueryable<T> as DataSource
- IEnumerable<T> VS IList<T> VS IQueryable<T>
- What interface should my service return? IQueryable, IList, IEnumerable?
- Should I return IEnumerable<T> or IQueryable<T> from my DAL?
如您所见,仅关于 SO 的主题就有一些很好的资源,但有一个问题/问题的一部分我仍然不确定是否已通读这些内容。
我主要关心的是 IEnumerable 与 IQueryable 的问题,更具体地说,是 DAL 与它的消费者之间的耦合。
我发现对这两个界面提出了不同的意见,这些意见都很棒。但是,我担心 DAL 返回 IQueryable 的含义。据我了解,IQueryable 建议/暗示引擎盖下有一个 Linq 提供程序。这是第一个问题——如果 DAL 突然需要来自非 Linq 提供的源的数据怎么办?以下是可行的,但它更像是一种黑客攻击吗?
public static IQueryable<Product> GetAll()
{
// this function used to use a L2S context or similar to return data
// from a database, however, now it uses a non linq provider
// simulate the non linq provider...
List<Product> results = new List<Product> { new Product() };
return results.AsQueryable();
}
所以我可以使用 AsQueryable() 扩展,尽管我不承认确切知道它的作用?我总是把 IQueryables 想象成底层的表达式树,我们可以根据需要附加它们,直到我们准备好执行我们的查询并获取结果。
我可以通过将函数的返回类型更改为 IEnumerable 来纠正这个问题。然后我可以从函数中返回 IQueryable,因为它继承了 IEnumerable,并且我可以保持延迟加载。我失去的是追加到查询表达式的能力:
var results = SomeClass.GetAll().Where(x => x.ProductTypeId == 5);
当返回 IQueryable 时,据我所知,这只会附加表达式。返回 IEnumerable 时,尽管保持延迟加载,但必须对表达式进行求值,以便将结果带入内存并进行枚举以过滤掉不正确的 ProductTypeId。
其他人如何解决这个问题?
- 在 DAL 中提供更多功能 - GetAllByProductType、GetAllByStartDate 等
-
提供一个接受谓词的重载?即
public static IEnumerable<Product> GetAll(Predicate<Product> predicate) { List<Product> results = new List<Product> { new Product() }; return results.Where(x => predicate(x)); }
最后一部分(抱歉,我知道,这个问题真的很长!)。
在我检查的所有问题中,我发现 IEnumerable 是最受推荐的,但是延迟加载对于数据上下文可用的要求呢?据我了解,如果您的函数返回 IEnumerable,但您返回 IQueryable,则 IQueryable 依赖于基础数据上下文。因为这个阶段的结果实际上是一个表达式并且没有任何东西被带入内存,所以你不能保证 DAL 的/函数的使用者将要执行查询,也不保证什么时候。那么我是否必须以某种方式保留结果源自可用的上下文实例?这就是工作单元模式发挥作用的方式/原因吗?
为了清楚起见,问题摘要(是否搜索过“?”...):
- 如果使用 IQueryable 作为返回类型,您的 UI/业务逻辑与 Linq 提供程序的耦合是否过于紧密?
- 如果您突然需要从非 Linq 提供的源返回数据,使用 AsQueryable() 扩展是个好主意吗?
- 任何人都有一个很好的链接来描述例如将标准列表转换为 AsQueryable 的工作原理,它实际上做了什么?
- 您如何处理由业务逻辑提供给 DAL 的额外过滤要求?
- 似乎 IEnumerable 和 IQueryable 的延迟加载取决于维护底层提供程序,我应该使用工作单元模式还是其他方式来处理这个问题?
提前非常感谢!
【问题讨论】:
-
我认为不应该围绕 IQueryable 的功能建立延迟加载机制。
-
@Urban 你能帮我解释一下吗?我想,如果我理解你,我同意。我们当前的项目正在返回 IQueryable,尽管它在业务层甚至表示层中提供了额外的功能和便利性,但感觉并不正确。
-
我认为虽然让 IQueryable 将负载推迟到最后可能的时间是很好的,但这实际上是在您构建查询时进行的。正如您已经说过的,分发它需要您保持上下文的活力,您可能无法保证。我宁愿使用一个定义和执行我的查询并让它返回一个 IEnumerable 的类。不过我可能错了:)
-
@Urban,我完全同意,但请记住,只需将函数更改为 IEnumerable
,我仍然可以保持查询的延迟加载。我仍然面临必须维护我认为的上下文的问题? -
您的 IEnumerable
将是一个完全加载的列表。您可能会在方法中使用列表并将其作为 IEnumerable 或 IList 传递出去
标签: c# visual-studio-2010 .net-4.0 data-access-layer