Entity framework 什么';.ToList()、.AsEnumerable()和AsQueryable()之间的区别是什么?
我知道LINQ对实体和LINQ对对象的一些区别,第一个实现了Entity framework 什么';.ToList()、.AsEnumerable()和AsQueryable()之间的区别是什么?,entity-framework,entity-framework-4,linq-to-entities,entity-framework-5,Entity Framework,Entity Framework 4,Linq To Entities,Entity Framework 5,我知道LINQ对实体和LINQ对对象的一些区别,第一个实现了IQueryable,第二个实现了IEnumerable,我的问题范围在EF 5之内 我的问题是这三种方法的技术区别是什么?我看到在很多情况下,它们都能工作。我还看到使用它们的组合,如.ToList().AsQueryable() 这些方法到底意味着什么 是否存在任何性能问题或会导致使用其中一个而不是另一个的问题 例如,为什么要使用.ToList().AsQueryable()而不是.AsQueryable() ToList()将成为内
IQueryable
,第二个实现了IEnumerable
,我的问题范围在EF 5之内
我的问题是这三种方法的技术区别是什么?我看到在很多情况下,它们都能工作。我还看到使用它们的组合,如.ToList().AsQueryable()
.ToList().AsQueryable()
而不是.AsQueryable()
希望这能让它更清楚一点。关于这一点,有很多话要说。让我重点关注
AsEnumerable
和AsQueryable
,并在此过程中提到ToList()
这些方法的作用是什么?
AsEnumerable
和AsQueryable
分别转换为IEnumerable
或IQueryable
。我说“铸造”或“转化”是有原因的:
- 当源对象已经实现了目标接口时,源对象本身将返回,但会强制转换到目标接口。换句话说:类型没有改变,但编译时类型是
- 当源对象未实现目标接口时,源对象将转换为实现目标接口的对象。因此,类型和编译时类型都发生了更改
void ReportTypeProperties(T obj)
{
WriteLine(“编译时类型:{0}”,typeof(T).Name);
WriteLine(“实际类型:{0}”,obj.GetType().Name);
}
让我们尝试一个任意的linq to sql表
,它实现了IQueryable
:
ReportTypeProperties(context.Observations);
ReportTypeProperties(context.Observations.AsEnumerable());
ReportTypeProperties(context.Observations.AsQueryable());
结果是:
编译时类型:表'1
实际类型:表` 1
编译时类型:IEnumerable`1
实际类型:表` 1
编译时类型:IQueryable`1
实际类型:表` 1
您可以看到,表类本身总是返回的,但其表示形式会发生变化
现在是一个实现了IEnumerable
,而不是IQueryable
的对象:
var ints=new[]{1,2};
ReportTypeProperties(ints);
ReportTypeProperties(ints.AsEnumerable());
ReportTypeProperties(ints.AsQueryable());
结果是:
编译时类型:Int32[]
实际类型:Int32[]
编译时类型:IEnumerable`1
实际类型:Int32[]
编译时类型:IQueryable`1
实际类型:EnumerableQuery`1
就在那里AsQueryable()
已将数组转换为,它“将IEnumerable
集合表示为IQueryable
数据源”(MSDN)
有什么用?
AsEnumerable
经常用于从任何IQueryable
实现切换到LINQ to objects(L2O),这主要是因为前者不支持L2O具有的功能。有关更多详细信息,请参阅
例如,在实体框架查询中,我们只能使用数量有限的方法。因此,例如,如果我们需要在查询中使用我们自己的方法,我们通常会编写如下代码
var query = context.Observations.Select(o => o.Id)
.AsEnumerable().Select(x => MySuperSmartMethod(x))
ToList
——它将IEnumerable
转换为列表
——也经常用于此目的。使用AsEnumerable
与ToList
相比的优点是AsEnumerable
不执行查询AsEnumerable
保留延迟执行,不构建通常无用的中间列表
另一方面,当需要强制执行LINQ查询时,ToList
可以作为一种方法
AsQueryable
可用于使可枚举集合接受LINQ语句中的表达式。有关更多详细信息,请参见此处:
关于药物滥用的说明!
AsEnumerable
就像药物一样有效。这是一个快速解决方案,但要付出代价,而且不能解决根本问题
在许多堆栈溢出的答案中,我看到人们应用aseneumerable
来解决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
fix:
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()
context.Observations.AsEnumerable().Select(x => x)
.AsQueryable()
var query = context.Observations.Select(o => o.Id)
.AsEnumerable().Select(x => x.ToString())
.AsQueryable()
.Where(...)
void DoSomething<T>(IEnumerable<T> objects){
var single = objects.First(); //load everything into memory before .First()
...
}
void DoSomething<T>(IEnumerable<T> objects){
T single;
if (objects is IQueryable<T>)
single = objects.AsQueryable().First(); // SELECT TOP (1) ... is used
else
single = objects.First();
}
T single = objects is IQueryable<T> q?
q.First():
objects.First();