简体   繁体   English

List <T>和IQueryable <T>之间的执行差异

[英]Difference in execution between List<T> and IQueryable<T>

I'm trying to write a generic database update method that can take advantage of IQueryable to whittle down the number of returned entities before processing. 我正在尝试编写一个通用数据库更新方法,该方法可以利用IQueryable在处理之前减少返回实体的数量。 So for a part of the code, I tried this ( b.ToType() returns a P ): 所以对于部分代码,我尝试了这个( b.ToType()返回一个P ):

IQueryable<B> bs = bcontext.Set<B>();
IQueryable<P> ps = pcontext.Set<P>();
List<P> inserts = ps.Except(bs.Select(b => b.ToType())).Take(500).ToList();

When I write it like this, I get System.ArgumentNullException: 'Value cannot be null.' 当我像这样写它时,我得到System.ArgumentNullException: 'Value cannot be null.'

However, it works when I go ahead and enumerate the DBSets before doing the Except like this: 然而,当我继续前进,做之前枚举DBSets它的工作原理Except这样的:

List<B> bs = bcontext.Set<B>().ToList();
List<P> ps = pcontext.Set<P>().ToList();
List<P> inserts = ps.Except(bs.Select(b => b.ToType())).Take(500).ToList();

Both ways compile fine, but I get the exception the first way and not the second way. 两种方式编译都很好,但我得到了第一种方式的异常,而不是第二种方式。 Is there some limitation to what you can put in an IQueryable expression tree that doesn't exist with Lists? 你可以放入一个与列表不存在的IQueryable表达式树有什么限制吗?

Generally IQueryable is used to avoid the execution of the query until it's narrowed down to the exact point where we will get the actual required data. 通常,IQueryable用于避免执行查询,直到它缩小到我们将获得实际所需数据的确切点。

Compared to List, when we do .ToList() the query is executed and we have all the result in memory from where on you can query or filter out the results. 与List相比,当我们执行.ToList()时,执行查询并将所有结果存储在内存中,您可以从中查询或过滤掉结果。

Depending upon the performance on the client side or the network correct option can be chosen. 根据客户端或网络的性能,可以选择正确的选项。 Doing .ToList will give you the result in memory from where on you can perform the operations. 执行.ToList将在内存中为您提供执行操作的结果。

For the reference ill redirect you to this answer: Differences between IQueryable, List, IEnumerator? 为了参考,ill会将你重定向到这个答案: IQueryable,List,IEnumerator之间的区别?

Following is the implementation of the IQueryable<T>.Except , check here : 以下是IQueryable<T>.Except的实现。 IQueryable<T>.Except ,请点击此处

public static IQueryable<TSource> Except<TSource>(this IQueryable<TSource> source1, IEnumerable<TSource> source2) {
            if (source1 == null)
                throw Error.ArgumentNull("source1");
            if (source2 == null)
                throw Error.ArgumentNull("source2");
            return source1.Provider.CreateQuery<TSource>( 
                Expression.Call(
                    null, 
                    GetMethodInfo(Queryable.Except, source1, source2),
                    new Expression[] { source1.Expression, GetSourceExpression(source2) }
                    ));
        }

Prime difference between the working of the IQueryable<T> and List<T> , Queryable type internally works with Expression<Func<T>> , since its getting executed remotely, in your case using the provider, when List<T> works with Func<T> , since its an in memory processing. IQueryable<T>List<T>的工作之间的主要区别,可查询类型在内部与Expression<Func<T>> ,因为当你使用提供程序时,它可以远程执行,当List<T>使用时Func<T> ,因为它在内存处理中。 When it comes to remote processing something like EF translates into relevant Sql query for processing, when in your case the following translates to null during remote processing: bs.Select(b => b.ToType()) . 当涉及到远程处理时,像EF这样的东西转换成相关的Sql查询进行处理,在你的情况下,以下在远程处理期间转换为nullbs.Select(b => b.ToType())

Following is the implementation of IEnumerable<T>.Except , check here : 以下是IEnumerable<T>.Except ,请点击此处

public static IEnumerable<TSource> Except<TSource>(this IEnumerable<TSource> first, 
                                                   IEnumerable<TSource> second) 
{
    if (first == null) throw Error.ArgumentNull("first");
    if (second == null) throw Error.ArgumentNull("second");
    return ExceptIterator<TSource>(first, second, null);
}

Except itself is internally a set operation, even for List<T> call to Except(null) will lead to same exception. Except它本身是一个set操作,即使对于List<T>Except(null)调用也会导致相同的异常。

As you have seen the definition of the IQueryable<T>.Except , its important to understand the difference in processing of the Expression and Func , Expression is more about what to do and Func is about how to do check this . 正如您已经看到IQueryable<T>.Except的定义,它对于理解Expression and Func处理差异很重要,Expression更多的是关于如何做,而Func是关于如何检查它的

For a simple var intList = new List<int>{1,2,3} , this is what Queryable expression looks like (as shown in the attached image). 对于一个简单的var intList = new List<int>{1,2,3} ,这就是Queryable表达式的样子(如附图所示)。

Essence remains check what your provider is internally translating the Queryable Expression into, which is leading to null and thus exception while processing Essence仍会检查您的提供程序在内部将可查询表达式转换为哪些内容,这会导致null并因此在处理时出现异常

在此输入图像描述

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM