关于c#:List< T>之间的执行差异

Difference in execution between List<T> and IQueryable<T>

我正在尝试编写一个通用的数据库更新方法,它可以利用iQueryable在处理之前减少返回实体的数量。因此,对于代码的一部分,我尝试了这个方法(b.ToType()返回P

1
2
3
4
5
6
IQueryable bs = bcontext.Set();
IQueryable<p>
 ps = pcontext.Set<p>
();
List<p>
 inserts = ps.Except(bs.Select(b => b.ToType())).Take(500).ToList();

当我这样写的时候,我得到了System.ArgumentNullException: 'Value cannot be null.'

但是,当我在这样做Except之前继续枚举dbset时,它是有效的:

1
2
3
4
5
6
List bs = bcontext.Set().ToList();
List<p>
 ps = pcontext.Set<p>
().ToList();
List<p>
 inserts = ps.Except(bs.Select(b => b.ToType())).Take(500).ToList();

两种方法都编译得很好,但是我第一种方法得到异常,而不是第二种方法。对于不存在于列表中的IQueryable表达式树,是否存在一些限制?


下面是IQueryable.Except的实现,请查看:

1
2
3
4
5
6
7
8
9
10
11
12
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) }
                    ));
        }

IQueryableList的工作之间的主要区别是,可查询类型内部与Expression>一起工作,因为它是远程执行的,在您使用提供程序的情况下,当ListFunc一起工作时,因为它是内存处理。当涉及到远程处理时,比如ef转换成相关的SQL查询进行处理,在您的情况下,在远程处理期间,以下转换为nullbs.Select(b => b.ToType())

以下是IEnumerable.Except的实施情况,请查看:

1
2
3
4
5
6
7
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本身就是一个集合操作,即使对于List调用Except(null)也会导致相同的异常。

正如您所看到的IQueryable.Except的定义,理解Expression and Func处理过程中的差异非常重要,表达式更多地是关于要做什么,func是关于如何检查这一点。

对于一个简单的var intList = new List{1,2,3},这就是可查询表达式的样子(如所附图片所示)。

本质仍然是检查提供者在内部将可查询表达式转换为什么,这将导致空值,从而在处理时出现异常。

enter image description here


通常,iQueryable用于避免执行查询,直到它缩小到我们将获得实际所需数据的精确点为止。

与list相比,当我们执行.tolist()时,查询将被执行,并且我们在内存中有所有的结果,从中您可以查询或筛选出结果。

根据客户端的性能或网络,可以选择正确的选项。doing.tolist将在内存中提供结果,从中可以执行操作。

对于参考资料,我会将您重定向到此答案:iQuery、List和IEnumerator之间的区别?