我知道LINQ到实体和LINQ to对象的一些差异,第一实现IQueryable
和第二实现IEnumerable
,我的问题范围EF 5中。
我的问题是什么的那些3种方法的技术差异(S)? 我看到,在许多情况下,他们都工作。 我也看到使用它们的组合,像.ToList().AsQueryable()
什么这些方法的意思是,到底是什么?
是否有任何性能问题或一些会导致使用一个比其他的?
为什么人会使用,例如, .ToList().AsQueryable()
代替.AsQueryable()
有很多说这个。 让我专注于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到SQL Table<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
实施LINQ到对象(L2O),主要是因为前者不支持L2O具有的功能。 欲了解更多详情,请参阅什么是AsEnumerable()的一个LINQ实体的效果? 。
例如,在一个实体框架的查询,我们只能使用方法个数有限制。 所以,如果,例如,我们需要使用我们自己的方法之一,在查询中,我们通常喜欢写东西
var query = context.Observations.Select(o => o.Id)
.AsEnumerable().Select(x => MySuperSmartMethod(x))
ToList
-其中转换IEnumerable<T>
到一个List<T>
-常常用于此目的,以及。 使用的优点AsEnumerable
与ToList
是AsEnumerable
不执行查询。 AsEnumerable
保留延迟执行,并且不建立一个经常无用的中间列表。
在另一方面,当LINQ查询的强制执行是需要的, ToList
可以是一个办法做到这一点。
AsQueryable
可用于制造可枚举集合接受LINQ语句表达。 在这里看到更多的细节: 我是否真的需要在收集使用AsQueryable已()? 。
注意药物滥用!
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结果集的减小。
现在假定用户只希望看到的日期部分CreateDate
。 在实体框架,你很快就会发现...
.Select(x => new { x.Name, x.CreateDate.Date })
...不支持(在写作的时候)。 啊,幸好还有的AsEnumerable
修复:
context.MyLongWideTable.AsEnumerable()
.Where(x => x.Type == "type")
.Select(x => new { x.Name, x.CreateDate.Date })
当然,它运行时,可能。 但是它拉整个表到内存中,然后应用过滤器和预测。 那么,大多数人有足够的智慧做Where
第一:
context.MyLongWideTable
.Where(x => x.Type == "type").AsEnumerable()
.Select(x => new { x.Name, x.CreateDate.Date })
不过还是所有列取出的第一和投影是在内存中完成。
真正的解决方法是:
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
实现了。
具体实现
到目前为止,这只是对Queryable.AsQueryable
和Enumerable.AsEnumerable
扩展方法。 但当然,任何人都可以写名称相同(和功能)实例方法或扩展方法。
实际上,特定的一个常见的例子AsEnumerable
扩展方法是DataTableExtensions.AsEnumerable
。 DataTable
未实现IQueryable
或IEnumerable
,所以常规的扩展方法不适用。
在内存ToList()将是一切,然后你会努力。 所以,ToList()。其中(适用于一些过滤器)本地执行。 AsQueryable已()就可以被发送到数据库的应用将远程执行一切即过滤器。 直到你执行它可查询没有做任何事情。 ToList,但立即执行。
另外,看看这个答案为什么使用AsQueryable已()代替名单()? 。
编辑:另外,你的情况,一旦你做ToList(),然后每一个后续操作是本地的,包括AsQueryable已()。 一旦你开始本地执行不能切换到远程。 希望这使得它一点点清晰。
文章来源: What's the difference(s) between .ToList(), .AsEnumerable(), AsQueryable()?