我知道LINQ到实体和LINQto对象的一些不同之处,这是第一个实现的。IQueryable
和第二个工具IEnumerable
我的问题范围在EF 5之内。
我的问题是,这三种方法的技术区别是什么?如.ToList().AsQueryable()
。
.ToList().AsQueryable()
而不是.AsQueryable()
?发布于 2018-03-26 15:40:35
集中讨论AsEnumerable
和AsQueryable
提到ToList():
AsEnumerable
和AsQueryable
铸造或转换为IEnumerable
或IQueryable
分别。
让我举几个例子来说明这一点。
void ReportTypeProperties<T>(T obj)
{
Console.WriteLine("Compile-time type: {0}", typeof(T).Name);
Console.WriteLine("Actual type: {0}", obj.GetType().Name);
}
让我们尝试一个任意的Linq到SQLTable<T>
,实现IQueryable
:
ReportTypeProperties(context.Observations);
ReportTypeProperties(context.Observations.AsEnumerable());
ReportTypeProperties(context.Observations.AsQueryable());
结果:
Compile-time type: Table`1
Actual type: Table`1
Compile-time type: IEnumerable`1
Actual type: Table`1
Compile-time type: IQueryable`1
Actual type: Table`1
可以看到表类本身总是被返回,但是它的表示形式会改变。
现在是实现IEnumerable
,不是IQueryable
:
var ints = new[] { 1, 2 };
ReportTypeProperties(ints);
ReportTypeProperties(ints.AsEnumerable());
ReportTypeProperties(ints.AsQueryable());
结果:
Compile-time type: Int32[]
Actual type: Int32[]
Compile-time type: IEnumerable`1
Actual type: Int32[]
Compile-time type: IQueryable`1
Actual type: EnumerableQuery`1
AsQueryable()
将数组转换为EnumerableQuery,它“表示IEnumerable<T>
集合为IQueryable<T>
数据源。“。(MSDN)
AsEnumerable
经常用于从任何IQueryable
实现LINQtoObjects(L2O),主要是因为前者不支持L2O所具有的函数。
例如,在实体框架查询中,我们只能使用有限数量的方法。因此,例如,如果我们需要在查询中使用自己的方法之一,我们通常会编写如下
var query = context.Observations.Select(o => o.Id)
.AsEnumerable().Select(x => MySuperSmartMethod(x))
ToList
-转换IEnumerable<T>
转到List<T>
-也经常用于这一目的。使用优势AsEnumerable
v.V.ToList
那是AsEnumerable
不执行查询。AsEnumerable
保留延迟执行,并且不构建通常无用的中间列表。
另一方面,当需要强制执行LINQ查询时,ToList
也能做到这一点。
AsQueryable
可用于使LINQ语句中的可枚举集合接受表达式。
AsEnumerable
就像毒品一样。这是一个快速的解决方法,但需要付出代价,而且不能解决根本的问题。
在许多堆栈溢出的答案中,我看到人们正在申请AsEnumerable
若要解决LINQ表达式中不支持的方法的任何问题,请执行以下操作。但价格并不总是明确的。例如,如果这样做:
context.MyLongWideTable // A table with many records and columns
.Where(x => x.Type == "type")
.Select(x => new { x.Name, x.CreateDate })
.所有东西都被巧妙地转换成SQL语句滤光片(Where
)和项目(Select
)。也就是说,SQL结果集的长度和宽度都会减少。
真正的解决办法是:
context.MyLongWideTable
.Where(x => x.Type == "type")
.Select(x => new { x.Name, DbFunctions.TruncateTime(x.CreateDate) })
现在有个重要的警告。当你做的时候
context.Observations.AsEnumerable()
.AsQueryable()
您将最终得到表示为IQueryable
...。(因为这两种方法只转换而不转换)。
但当你这么做的时候
context.Observations.AsEnumerable().Select(x => x)
.AsQueryable()
结果如何?
大Select
产生一个WhereSelectEnumerableIterator
...。这是一个内部.net类,它实现IEnumerable
,不IQueryable
...。因此,转换到另一种类型已经发生,并且随后的AsQueryable
再也不能返回原始源了。
这意味着使用AsQueryable
是无法神奇地注入查询提供程序将它的特定特性变成可枚举的。假设你知道
var query = context.Observations.Select(o => o.Id)
.AsEnumerable().Select(x => x.ToString())
.AsQueryable()
.Where(...)
WHERE条件将永远不会转换为SQL。AsEnumerable()
然后是LINQ语句,明确地切断了与实体框架查询提供程序的连接。
我故意展示这个例子,因为我在这里看到了一些问题,比如人们试图“注入”Include
通过调用AsQueryable
。它编译和运行,但是它什么也不做,因为基础对象没有Include
实现不再。
发布于 2018-03-26 17:00:19
ToList()
AsEnDigable()
Func<TSource, bool>
AsQueryable()
Expression<Func<TSource, bool>>
AsQueryable()
通常比AsEnumerable()
因为它首先生成T-SQL,其中包括Linq中的所有WHERE条件。https://stackoverflow.com/questions/-100003219
复制相似问题