IEnumerable与IQueryable的业务逻辑或DAL返回类型

Smu*_*202 24 c# data-access-layer .net-4.0 visual-studio-2010

我知道之前已经问过这些问题,我将首先列出其中一些问题(我到目前为止已经阅读过的):

正如你所看到的那样,关于这个主题的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();
}
Run Code Online (Sandbox Code Playgroud)

所以我可以使用AsQueryable()扩展,虽然我不承认确切知道这是做什么的?我总是将IQueryables想象为底层表达式树,我们可以根据需要追加它们,直到我们准备好执行查询并获取结果.

我可以通过将函数的返回类型更改为IEnumerable来纠正此问题.然后我可以从函数返回IQueryable,因为它继承了IEnumerable,我得保持延迟加载.我失去的是能够附加到查询表达式:

var results = SomeClass.GetAll().Where(x => x.ProductTypeId == 5);
Run Code Online (Sandbox Code Playgroud)

返回IQueryable时,据我所知,这只会附加表达式.当返回的IEnumerable,尽管保持了延迟加载,表达必须进行评价,其结果将被带到内存和枚举通过过滤掉不正确ProductTypeIds.

其他人如何绕过这个?

  • 在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));
    }
    
    Run Code Online (Sandbox Code Playgroud)

最后一部分(对不起,我知道,真的很长的问题!).

我发现在我检查过的所有问题中IEnumerable是最推荐的,但是延迟加载对datacontext的可用要求怎么样?据我了解,如果你的函数返回IEnumerable,但是你返回IQueryable,那么IQueryable依赖于底层的datacontext.因为此阶段的结果实际上是一个表达式,并且没有任何内容被带入内存,所以无法保证DAL的/函数的使用者将执行查询,也不能保证.那么我是否必须以某种方式保留结果来源的上下文实例?这是工作单元模式如何/为何发挥作用?

为清楚起见问题摘要(搜索"?"......):

  1. 如果使用IQueryable作为返回类型,您是否将UI /业务逻辑与Linq提供商紧密耦合?
  2. 如果您突然需要从非Linq提供的源返回数据,那么使用AsQueryable()扩展是一个好主意吗?
  3. 任何人都有一个很好的链接描述如何将标准列表转换为AsQueryable工作,它实际上做了什么?
  4. 如何处理业务逻辑为DAL提供的其他过滤要求?
  5. 似乎IEnumerable和IQueryable的延迟加载都需要维护底层提供者,我应该使用工作单元模式还是其他什么来处理这个问题?

非常感谢提前!

Mar*_*ell 19

  1. 好吧,你并没有严格地与任何特定的提供商联系,但作为一种重写:你不能轻易地测试代码,因为每个提供商都有不同的支持功能(意思是:哪一个适用于另一个可能不适用于另一个- 甚至像这样的东西.Single())
  2. 如果您有任何关于不断变化的供应商的问题,我不这么认为- 见上文
  3. 它只是提供了一个.Compile()在任何lambdas 上使用的装饰包装器,而是使用LINQ-to-Objects.注意LINQ到对象有更多的比任何其他供应商的支持,所以这不会是一个问题-除了它意味着什么"嘲笑"使用这种方法并不真正考验你的实际代码在所有,并主要是没有意义的( IMO)
  4. 是的,狡猾 - 见下文
  5. 是的,狡猾 - 见下文

就个人而言,我更喜欢这里定义良好的API,它们采用已知参数并返回加载 List<T>IList<T>(或类似)结果; 这为您提供了一个可测试/可模拟的API,并且不会让您受到延迟执行(封闭连接地狱等)的支配.它还意味着提供程序之间的任何差异都在内部处理,以实现数据层.它还更适合调用Web服务等场景.

简而言之; 在IEnumerable<T>和之间做出选择IQueryable<T>,我不选择 - 选择使用IList<T>List<T>.如果我需要额外的过滤,那么:

  1. 我将通过参数将其添加到现有API,并在我的数据层中进行过滤
  2. 我会接受超大数据回来,然后我需要在调用者处过滤掉

  • @ Smudge202列表的一个巨大优势 - 调用者*知道*他们可以便宜地查询长度,并根据自己的喜好迭代它,并便宜地获取第3项,等等 (2认同)

归档时间:

查看次数:

4214 次

最近记录:

14 年,3 月 前