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

时间:2018-07-17 21:21:48

标签: c# linq

我正在尝试编写一种通用的数据库更新方法,该方法可以利用IQueryable在处理之前减少返回的实体的数量。因此,对于一部分代码,我尝试了一下(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();

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

但是,当我像这样进行Except之前枚举DBSet时,它是可行的:

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

两种方法都可以编译,但是我在第一种方法而不是第二种方法上遇到了异常。可以放入列表不存在的IQueryable表达式树的内容有什么限制吗?

2 个答案:

答案 0 :(得分:2)

通常,IQueryable用于避免执行查询,直到将查询范围缩小到可以获取实际所需数据的确切位置为止。

与List相比,当我们执行.ToList()时,将执行查询,并将所有结果存储在内存中,您可以从中查询或过滤出结果。

取决于客户端的性能或网络,可以选择正确的选项。执行.ToList会将结果存储在内存中,您可以从该位置执行操作。

对于不适的参考文献,您将您重定向至此答案: Differences between IQueryable, List, IEnumerator?

答案 1 :(得分:2)

以下是IQueryable<T>.Except的实现,请检查here

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

IQueryable<T>List<T>的主要工作区别在于,可查询类型在内部与Expression<Func<T>>一起使用,因为在{{1 }}与List<T>一起使用,因为它在内存中进行处理。当涉及到远程处理时,例如EF之类的内容会转换为相关的Sql查询以进行处理,而在您的情况下,以下内容将在远程处理中转换为Func<T>null

以下是bs.Select(b => b.ToType())的实现,请检查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); } 本身在内部是set操作,即使对Except的{​​{1}}调用也会导致相同的异常。

您已经看到List<T>的定义,这对于理解Except(null)的处理很重要,Expression的主要作用是做什么,而Func的方法是检查{{ 3}}。

对于简单的IQueryable<T>.Except,这就是Queryable表达式的样子(如附图所示)。

本质仍然存在,请检查您的提供程序在内部将Queryable Expression转换为什么,这将导致null并因此在处理时出现异常

this