我知道之前已经问过这些问题,我首先会列出其中一些问题(我到目前为止已经阅读过):
正如你所看到的那样,关于这个主题的SO有一些很好的资源,但有一个问题/部分的问题,我仍然不确定是否已经阅读了这些。
我主要关注的是IEnumerable vs 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时,尽管保持了延迟加载,但必须对表达式进行求值,以便将结果带入内存并枚举,以过滤掉不正确的ProductTypeIds。
其他人如何绕过这个?
提供接受谓词的重载?即。
public static IEnumerable<Product> GetAll(Predicate<Product> predicate)
{
List<Product> results = new List<Product> { new Product() };
return results.Where(x => predicate(x));
}
最后一部分(对不起,我知道,问题很长!)。
我发现IEnumerable是我检查的所有问题中最推荐的,但是延迟加载对datacontext可用的要求怎么样?据我了解,如果你的函数返回IEnumerable,但是你返回IQueryable,那么IQueryable依赖于底层的datacontext。因为此阶段的结果实际上是一个表达式并且没有任何内容被带入内存,所以您不能保证DAL的/函数的使用者将执行查询,也不能保证。那么我是否必须以某种方式保留结果来源的上下文实例?这是工作单元模式如何/为何发挥作用?
为清晰起见问题摘要(搜索“?”......):
提前多多感谢!
答案 0 :(得分:19)
.Single()
).Compile()
的装饰包装器,而是使用LINQ-to-Objects。注意LINQ-to-Objects比任何其他提供者都支持更多,所以这不是问题 - 除了它意味着使用这种方法的任何“模拟”都不会真正测试你的实际代码 at all 并且在很大程度上毫无意义(IMO)就个人而言,我更喜欢定义良好的API,它们采用已知参数并返回加载 List<T>
或IList<T>
(或类似)结果;这为您提供了一个可测试/可模拟的API,并且不会让您受到延迟执行(封闭连接地狱等)的支配。它还意味着提供程序之间的任何差异都在内部处理到数据层的实现。它还更适合调用Web服务等场景。
总之;如果在IEnumerable<T>
和IQueryable<T>
之间进行选择,则我不会选择 - 而是选择使用IList<T>
或List<T>
。如果我需要额外的过滤,那么: