本文导读:
用Linq来操作集合的时候会用到AsQueryable()和AsEnumerable(),何时该用AsQueryable()和何时该用AsEnumerable(),或许存在些疑惑。
AsQueryable是在数据库中查询再返回数据,
AsEnumerable是从数据库读取全部数据再在程序中查询。
【第一遍】
AsQueryable是在数据库中查询再返回数据,
AsEnumerable是从数据库读取全部数据再在程序中查询。
【第二遍】
AsQueryable是在数据库中查询再返回数据,
AsEnumerable是从数据库读取全部数据再在程序中查询。
【第三遍】
AsQueryable是在数据库中查询再返回数据,
AsEnumerable是从数据库读取全部数据再在程序中查询。
在使用LINQ 进行数据集操作时,LINQ 不能直接从数据集对象中查询,因为数据集对象不支持LINQ 查询,所以需要使用AsEnumerable 方法返回一个泛型的对象以支持LINQ 的查询操作。
例如
string strcon = "Data Source=.\\\\SQLEXPRESS;Initial Catalog=Db_Example;Persist Security Info=True;User ID=sa;Password=sa";
SqlConnection con = new SqlConnection(strcon);
con.Open();
string strsql = "select * from SC,Course where SC.Cno=Course.Cno";
SqlDataAdapter da = new SqlDataAdapter(strsql,con);
DataSet ds = new DataSet();
da.Fill(ds, "mytable");
DataTable tables=ds.Tables["mytable"]; //创建表
var dslp = from d in tables.AsEnumerable() select d;//执行LINQ语句,这里的.AsEnumerable()是延迟发生,不会立即执行,实际上什么都没有发生
foreach(var res in dslp)
一、linq中AsEnumerable和AsQueryable的区别
1、AsEnumerable()是延迟执行的,实际上什么都没有发生,当真正使用对象的时候(例如调用:First, Single, ToList....的时候)才执行。 2、AsEnumerable将一个序列向上转换为一个IEnumerable, 强制将Enumerable类下面的查询操作符绑定到后续的子查询当中。 3、AsQueryable将一个序列向下转换为一个IQueryable, 它生成了一个本地查询的IQueryable包装。
4、AsEnumerable()延迟执行,不会立即执行。当你调用.AsEnumerable()的时候,实际上什么都没有发生。 5、ToList()立即执行 6、当你需要操作结果的时候,用.ToList(),否则,如果仅仅是用来查询不需要进一步使用结果集,并可以延迟执行,就用.AsEnumerable()/IEnumerable /IQueryable
7、AsEnumerable()虽然延迟执行,但还是访问数据库,而.ToList()直接取得结果放在内存中。比如我们需要显示两个部门的员工时,部门可以先取出放置在List中,然后再依次取出各个部门的员工,这时访问的效率要高一些,因为不需要每次都访问数据库去取出部门。 8、IQueryable实现了IEnumberable接口。但IEnumerable<T> 换成IQueryable<T>后速度提高很多。
9、IQueryable接口与IEnumberable接口的区别: IEnumerable<T> 泛型类在调用自己的SKip 和 Take 等扩展方法之前数据就已经加载在本地内存里了,而IQueryable<T> 是将Skip ,take 这些方法表达式翻译成T-SQL语句之后再向SQL服务器发送命令,它并不是把所有数据都加载到内存里来才进行条件过滤。 10、IEnumerable跑的是Linq to Object,强制从数据库中读取所有数据到内存先。
二、AsEnumerable和AsQueryable的实例
实例一
服务器端sql
--AsQueryable
Select
[Extent1].[id] AS [id]
FROM [dbo].[User] AS [Extent1]
Where [Extent1].[id] > 10
--AsEnumerable
Select
[Extent1].[id] AS [id],
[Extent1].[usn] AS [usn],
[Extent1].[pwd] AS [pwd],
[Extent1].[created] AS [created]
FROM [dbo].[User] AS [Extent1]
简述Linq中.ToList(), .AsEnumerable(), AsQueryable()的区别和用法
简述Linq中.ToList(), .AsEnumerable(), AsQueryable()的区别和用法
这3个方法的功能完全不同, 应按照具体业务场景使用.
AsQueryable()
lazy load 特性
以下是一段最常见的代码,
var products = db.Product.where(p => p.Type == "food").select(p => new { p.Id, p.Name, p.CreateTime});
products 的类型为 IQueryable<T>
, 因此不用加 .AsQueryable()
. 语句执行后不会立刻查询数据库, 而是在迭代使用 products 时才会查数据库, 具有 lazy load 的特性, 按需查数据库可提高程序效率.
迭代时上面的代码生成的 sql 语句类似:
select Id, Name, CreateTime from Product where Type = 'food'
对 products 再次使用 IQueryable 操作, 编译器会把结果合并为1条 sql 语句, 如下,
var products = db.Product.where(p => p.Type == "food").select(p => new { p.Id, p.Name, p.CreateTime});
var orderedProducts = products.OrderBy(p => p.CreateTime);
迭代时生成的 sql 语句类似:
select Id, Name, CreateTime from Product where Type = 'food' order by CreateTime
显式调用 AsQueryable()?
如果对没有继承 IQueryable 接口的类型使用 AsQueryable(), 会转换类型, 稍微消耗资源, 如下,
int[] array = new { 1, 2, 4, 5};
var enumArray = array.AsQueryable();
因为 Array 只继承了 IEnumerable, 没有继承 IQueryable, 所以会发生类型转换. 当然其中的泛型实现没有拆箱, 对性能影响不大. 但是没有必要, 因为 IQueryable 没有声明任何新方法.
其他有用的情况我暂时还没碰到, 请大家指教.
IQueryable的限制
此外 IQueryable 有诸多限制, 只支持数据库查询语法, 无法支持 Linq to object 的操作, 如以下2段代码会在运行时出错,
var products = db.Product
.Where(p => p.Type == "food")
.Select(p => new { p.Id, p.Name, p.CreateTime.Date});
// 如果改成 .Select(p => new { p.Id, p.Name, DbFunction.TruncateDate(p.CreateTime)})
// 就能正常运行.
var products = db.Product
.Where(p => p.Type == "food")
.Select(p => MyMethod(p));
.Select() 的返回类型为 IQueryable.
第1段代码, 我认为 IQueryable 还不够智能, 无法把 p.CreateTime.Date 转换为 sql 相关的 function, 而使用 DbFunctions 要求使用者了解同时熟悉 linq to entity 及 sql 的内置方法.
第2段代码, 生成 的 sql 无法返回 MyMethod 类型, 是可以理解的.
但是, 对代码加了 AsEnumerable() 后运行正常, 因为 IEnumerable 支持 Linq to object 的操作.
AsEnumerable()
同样支持 lazy load, 但不要滥用
同样是延迟查询, 与 AsQueryable() 区别是, 迭代时遇到 AsEnumerable() 会先进行 sql 查询, 所以对已查出来的结果当然能进行 Linq to object 操作.
但是, 千万不要为了方便而滥用 AsEnumerable(), 可能会严重消耗资源, 如下代码,
var products = db.Product.AsEnumerable()
.Select(p => new {p.Id, p.Name, p.CreateTime.Date});
上面的代码在查询时会把整个Product表的结果存放进内存, 然后进行 .Select 查询!!!
当我不熟悉 DbFunction 或者 要用自定义返回类型应该怎么办
正确的做法应该如下,
var products = db.Product
.Select(p => new {p.Id, p.Name, p.CreateTime})
.AsEnumerable()
.Select(p => MyMethod(p));
AsEnumerable()的限制
如果你写了以下代码,
var products = db.Product
.Select(p => new {p.Id, p.Name, p.CreateTime})
.AsEnumerable()
.Select(p => new {p.Id, p.Name, p.CreateTime.ToString()});
.AsQueryable()
.Where(p=> p.Name == "xxx");
那么最后的 .Where()永远不会执行!!!
因为在使用 AsQueryable().Where() 要求 Linq to entity 进行数据库查询, 但是第一次 AsEnumerable() 时已经进行了数据库查询并且断开连接, 并且查询结果已经作为实实在在的 object, 对 object 不可能再次使用 AsQueryable().Where() 叠加数据库查询!
看到评论指出 .AsEnumerable().AsQueryable().Where(...), Where条件也会生效. 确实文中这一部分描述有误.
实际情况是, 在迭代时遇到AsEnumerable()会先把数据装入内存, 之后调用AsQueryable().Where(), 但这时候底层的类型是IEmumerable而不是IQueryable, 所以框架会使用IEnumeralbe.Where(), 因此能够过滤数据. 然而, 当继续使用.Include(), .Where(i => DbFunctions...)等IQueryable独有的方法时, 框架会使用空实现, 没有效果.
ToList()
调用 ToList() 会立刻查询并保存结果, 而不会等到迭代时才查询. 作用和 lazy load 是对立的.
在需要得到完整结果后, 再处理的场景, 需要使用 ToList().
例如, 在返回mvc ActionResult 的时候, 要先使用 ToList(), 再作为 model 传给 view. 不知道 mvc 是出于什么考虑不支持在生成 html 的时候lazy load, 请大家指教!