IEnumerable的VS IQueryable的业务逻辑和DAL返回类型逻辑、类型、业务、VS

2023-09-07 11:27:25 作者:▲ 安于心*

我知道这些问题已经被问过,我将列出他们几个(​​那些至今我所读)启动:

的IEnumerable VS IQueryable的 List,的IList,IEnumerable的,IQueryable的,ICollection的,这是最灵活的返回类型? 返回的IEnumerable&LT; T&GT; VS IQueryable的&LT; T&GT; 的IEnumerable&LT; T&GT;作为返回类型 IEnumerable和IQueryable的 浏览与业务逻辑VS code WPF的IEnumerable&LT; T&GT; VS IQueryable的&LT; T&GT;作为数据源 IEnumerable<T> VS的IList&LT; T&GT; VS IQueryable的&LT; T&GT; What接口应我的服务回报? IQueryable的,IList的,IEnumerable的? Should我回到了IEnumerable&LT; T&GT;或IQueryable的&LT; T&GT;从我DAL?

正如你所看到的,有对如此孤独一些重要的资源上的问题,但有一个问题/我仍然不知道看了这些全部通过问题的部分。

我主要关心的IEnumerable VS IQueryable的问题,更具体地说是的连接的DAL层之间,它的的消费者的。

我发现不同的意见建议对于两个接口,这已经很大。不过,我关心的是一个DAL返回的IQueryable的影响。据我了解的IQueryable建议/意味着有引擎盖下LINQ提供程序。这是关注的头号 - 如果在DAL突然需要的数据从非的LINQ提供的源?以下会的工作,但它更多的是黑客?

 公共静态的IQueryable&LT;产品&GT; GETALL()
{
    //用于使用L2S上下文或类似的返回数据这个功能
    //从数据库中,不过,现在它采用了非LINQ提供程序

    //模拟非LINQ提供程序...
    名单&LT;产品&GT;结果=新名单,其中,产品&GT; { 新产品() };
    返回results.AsQueryable();
}
 

所以,我可以用AsQueryable已()扩展,虽然我不承认自己知道究竟这是什么呢?我总是想象IQueryables作为底层EX pression树我们,直到我们准备的执行的我们的查询和获取结果可以追加必要的。

我可以通过改变功能的IEnumerable的返回类型整治。然后,我可以从函数返回的IQueryable,因为它继承了IEnumerable,我也得到保持延迟加载。我失去的是要追加到查询EX pression的能力:

  VAR的结果= SomeClass.GetAll(),其中(X =&GT; x.ProductTypeId == 5)。
 

在返回IQueryable的,据我所知,这只会追加EX pression。当返回的IEnumerable,尽管保持了延迟加载,前pression要计算这样的结果将提请内存和枚举通过过滤掉不正确ProductTypeIds。

如何做其他人避开这个问题?

在DAL提供更多的功能 - GetAllByProductType,GetAllByStartDate,...等

提供一个接受predicates超载?即。

 公共静态的IEnumerable&LT;产品&GT; GETALL(predicate&LT;产品&GT; predicate)
{

    名单&LT;产品&GT;结果=新名单,其中,产品&GT; { 新产品() };
    返回results.Where(X =&GT; predicate(X));
}
 
最全数据结构详述 List VS IEnumerable VS IQueryable VS ICollection VS IDictionary

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

我发现了IEnumerable是最推荐的所有我查了问题,但对于推迟负荷的要求对​​一个DataContext可用?据我了解,如果你的函数返回的IEnumerable,但返回IQueryable的,IQueryable的将是依赖于底层的datacontext。因为结果在这个阶段实际上是一个前pression并没有什么已提请内存,你不能保证DAL的/功能的消费者会的执行的查询,也不能当。所以,我必须保持环境的情况下,结果来源于可不知何故?请问这是怎么/为什么工作模式的单位发挥作用的?

为清晰的问题汇总(做了搜索......?):

如果使用的IQueryable作为返回类型,你太紧密耦合的UI /业务逻辑到LINQ提供程序? 是使用AsQueryable已()扩展一个好主意,如果你突然需要从非的LINQ提供的源返回的数据? 在任何有描述例如如何将一个标准的名单AsQueryable已工作,它实际上呢?一个很好的链接 你怎么处理由业务逻辑在DAL提供额外的滤波要求? 看起来既IEnumerable和IQueryable的的延迟加载都受到维护底层的供应商,我应该使用的工作模式的单位或别的东西来处理呢?

感谢很多提前!

解决方案 好了,你是不是严格地耦合到任何特定的供应商,但作为一个重新措辞是:​​你不能轻易的测试的的code,因为每个供应商都有不同的支持特点(意为:什么对人们可能无法再正常工作 - 甚至像。单()) 在我不这么认为,如果没有的任意的问题,在你的心中对不断变化的供应商 - 见上 它只是提供了一个使用 .Compile()上的任何一个lambda表达式装饰包装,并使用LINQ到对象来代替。注意LINQ到对象拥有的更多的支持比任何其他供应商,所以这不会是一个问题 - 除非它意味着,使用这种方法的任何嘲笑不真正考验你的实际$ C $ç的所有的,并在很大程度上是毫无意义的(IMO) 是的,有难度的 - 见下文 是的,有难度的 - 见下文

就个人而言,我倒是preFER明确定义这里的API,采取已知的参数和返回的加载的名单,其中,T&GT; 的IList&LT; T&GT;结果(或类似);这给你一个可测试/ mockable API,并且不会让你在延迟执行(关闭的连接地狱等)的摆布。这也意味着,供应商之间的差异处理的内部的你的数据层的实现。这也使得更密切的配合调用方案,如网络服务等。

在短;鉴于的IEnumerable℃之间的选择; T&GT; 的IQueryable&LT; T&GT; ,我选择没有 - 而是选择使用的IList&LT; T&GT; 名单,其中,T&GT; 。如果我需要额外的滤波,然后:

我要补充的是,以现有的API通过参数,并做过滤我的数据层内 在我接受过大的数据是回来了,然后我需要在来电过滤掉

I know these questions have been asked before, I'll start by listing a few of them (the ones I've read so far):

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 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?

As you can see, there's some great resources on SO alone on the subject, but there is one question/section of the question I'm still not sure about having read these all through.

I'm primarily concerned with the IEnumerable vs IQueryable question, and more specifically the coupling between the DAL and it's consumers.

I've found varying opinions suggested regarding the two interfaces, which have been great. However, I'm concerned with the implications of a DAL returning IQueryable. As I understand it IQueryable suggest/implies that there is a Linq Provider under the hood. That's concern number one - what if the DAL suddenly requires data from a non-Linq provided source? The following would work, but is it more of a hack?

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();
}

So I can use the AsQueryable() extension though I don't admit to knowing exactly what this does? I always imagine IQueryables as being the underlying expression trees which we can append as necessary until we're ready to perform our query and fetch the results.

I could rectify this by changing the return type of the function to IEnumerable. I can then return IQueryable from the function because it inherits IEnumerable, and I get to keep the deferred loading. What I lose is the ability to append to the query expression:

var results = SomeClass.GetAll().Where(x => x.ProductTypeId == 5);

When returning IQueryable, as I understand it, this would simply append the expression. When returning IEnumerable, despite maintaining the deferred loading, the expression has to be evaluated so the results will be brought to memory and enumerated through to filter out incorrect ProductTypeIds.

How do other people get round this?

Provide more functions in the DAL - GetAllByProductType, GetAllByStartDate,... etc

Provide an overload that accepts predicates? i.e.

public static IEnumerable<Product> GetAll(Predicate<Product> predicate)
{

    List<Product> results = new List<Product> { new Product() };
    return results.Where(x => predicate(x));
}

One last part (Sorry, I know, really long question!).

I found IEnumerable to be the most recommended across all the questions I checked, but what about the deferred loadings' requirement for a datacontext to be available? As I understand it, if your function returns IEnumerable, but you return IQueryable, the IQueryable is reliant on an underlying datacontext. Because the result at this stage is actually an expression and nothing has been brought to memory, you cannot guarantee that the DAL's/function's consumer is going to perform the query, nor when. So do I have to keep the instance of the context that the results were derived from available somehow? Is this how/why the Unit of Work pattern comes into play?

Summary of the questions for clarity ( did a search for "?"...):

If using IQueryable as a return type, are you too tightly coupling your UI/Business Logic to Linq Providers? Is using the AsQueryable() extension a good idea if you suddenly need to return data from a non-Linq Provided source? Anyone have a good link describing how for example converting a standard list to AsQueryable works, what it actually does? How do you handle additional filtering requirements supplied by business logic to your DAL? It seems the deferred loading of both IEnumerable and IQueryable are subject to maintaining the underlying provider, should I be using a Unit of Work pattern or something else to handle this?

Thanks a lot in advance!

解决方案

well, you aren't strictly coupled to any specific provider, but as a re-phrasing of that: you can't easily test the code, since each provider has different supported features (meaning: what works for one might not work for another - even something like .Single()) I don't think so, if there is any question in your mind about ever changing provider - see above it just provides a decorated wrapper that uses .Compile() on any lambdas, and uses LINQ-to-Objects instead. Note LINQ-to-Objects has more support than any other provider, so this won't be an issue - except that it means that any "mocks" using this approach don't really test your actual code at all and are largely pointless (IMO) yeah, tricky - see below yeah, tricky - see below

Personally, I'd prefer well defined APIs here that take known parameters and return a loaded List<T> or IList<T> (or similar) of results; this gives you a testable/mockable API, and doesn't leave you at the mercy of deferred execution (closed connection hell, etc). It also means that any differences between providers is handled internally to the implementation of your data layer. It also makes a much closer fit for calling scenarios such as web-services, etc.

In short; given a choice between IEnumerable<T> and IQueryable<T>, I choose neither - opting instead to use IList<T> or List<T>. If I need additional filtering, then either:

I'll add that to the existing API via parameters, and do the filtering inside my data layer I'll accept that oversized data is coming back, which I then need to filter out at the caller