回答
Marc Gravell's answer是非常完整的,但我想我会但从用户的角度补充一些有关这一点,以及...
的主要区别,从用户的角度来看,是,当您使用IQueryable<T>
(使用支持正确内容的提供程序)时,可以节省大量资源。例如,如果您使用的是远程数据库(使用多个ORM系统),则可以通过两种方式从表中获取数据,其中一种返回IEnumerable<T>
,另一种返回IQueryable<T>
。比如说,你有一个产品表,并且你想要得到所有成本大于25美元的产品。
如果你这样做:
IEnumerable<Product> products = myORM.GetProducts();
var productsOver25 = products.Where(p => p.Cost >= 25.00);
这里会发生什么情况,是数据库加载所有的产品,并将它们通过线路到您的程序。您的程序然后过滤数据。本质上,数据库执行SELECT * FROM Products
,并将每个产品都返回给您。
有了正确的IQueryable<T>
提供商,在另一方面,你可以这样做:
IQueryable<Product> products = myORM.GetQueryableProducts();
var productsOver25 = products.Where(p => p.Cost >= 25.00);
的代码看起来是一样的,但这里的不同之处在于执行的SQL会SELECT * FROM Products WHERE Cost >= 25
。
从您的POV作为开发人员,这看起来是一样的。然而,从性能的角度来看,你可能只在网络上,而不是20000返回2条记录....
在本质上它的工作是非常相似的IEnumerable<T>
- 代表可查询的数据源 - 的不同之处在于各种LINQ方法(上Queryable
)可以更具体,建立使用Expression
树木,而不是代表查询(其是什么Enumerable
使用)。
表达式树可以由您选择的LINQ提供程序检查,并且变成实际的查询 - 尽管这本身就是一种黑色艺术。
这是真的下到ElementType
,Expression
和Provider
- 但在现实中,你很少需要关心这个作为用户。只有LINQ 的实施者需要知道血淋淋的细节。
重新评论;我不太清楚你想要什么,但考虑LINQ到SQL;这里的中心对象是DataContext
,它代表我们的数据库包装器。这通常每个表具有一个属性(例如,Customers
),并且一个表执行IQueryable<Customer>
。但我们并没有直接使用那么多,考虑:
using(var ctx = new MyDataContext()) {
var qry = from cust in ctx.Customers
where cust.Region == "North"
select new { cust.Id, cust.Name };
foreach(var row in qry) {
Console.WriteLine("{0}: {1}", row.Id, row.Name);
}
}
这成为(由C#编译器):
var qry = ctx.Customers.Where(cust => cust.Region == "North")
.Select(cust => new { cust.Id, cust.Name });
其再次解释(由C#编译器)为:
var qry = Queryable.Select(
Queryable.Where(
ctx.Customers,
cust => cust.Region == "North"),
cust => new { cust.Id, cust.Name });
重要的是,静态方法上Queryable
采取表达式树,而不是常规的IL,将其编译为对象模型。例如 - 只是在“去哪儿”,这为我们提供了一些类似:
var cust = Expression.Parameter(typeof(Customer), "cust");
var lambda = Expression.Lambda<Func<Customer,bool>>(
Expression.Equal(
Expression.Property(cust, "Region"),
Expression.Constant("North")
), cust);
... Queryable.Where(ctx.Customers, lambda) ...
没有编译器为我们做了很多?此对象模型可以分开被撕裂,检查是否意味着什么,以及由TSQL发电机重新组装 - 让这样的:
SELECT c.Id, c.Name
FROM [dbo].[Customer] c
WHERE c.Region = 'North'
(字符串可能最终作为参数,我不记得)
如果我们刚刚使用委托,这些都不可能。并且这个是点的Queryable
/IQueryable<T>
:它提供了使用表达式树的入口点。
所有这些都非常复杂,所以编译器对我们来说很好,很容易。
欲了解更多信息,请看“C# in Depth”或“LINQ in Action”,两者都提供这些主题的报道。
如果你不介意你可以用简单易懂的例子更新我(如果你有时间的话)。 – user190560 2009-10-16 15:44:11
您能否解释“GetQueryableProducts()的定义在哪里? “?”在Reed Copsey先生的回复中 – Pankaj 2011-12-13 18:31:38
享受到查询翻译表达式的路线是“黑色艺术本身”......很多事实对于那 – afreeland 2013-12-16 18:27:06
它允许进一步查询下行。如果这超出了服务边界的话,那么这个IQueryable对象的用户将被允许对它做更多的事情。
例如,如果您使用惰性加载与nhibernate这可能会导致图形加载/如果需要。
虽然和已经描述过的有关IQueryable(and also IEnumerable)
足够Marc Gravell,但我想在这里通过提供small example on IQueryable and IEnumerable
如添加更多一点许多用户要求它
例:我已经在数据库中创建了两个表
CREATE TABLE [dbo].[Employee]([PersonId] [int] NOT NULL PRIMARY KEY,[Gender] [nchar](1) NOT NULL)
CREATE TABLE [dbo].[Person]([PersonId] [int] NOT NULL PRIMARY KEY,[FirstName] [nvarchar](50) NOT NULL,[LastName] [nvarchar](50) NOT NULL)
表Employee
的Primary key(PersonId)
也表Person
下一页我加入ado.net实体模型在我的申请,并于该
public class SomeServiceClass
{
public IQueryable<Employee> GetEmployeeAndPersonDetailIQueryable(IEnumerable<int> employeesToCollect)
{
DemoIQueryableEntities db = new DemoIQueryableEntities();
var allDetails = from Employee e in db.Employees
join Person p in db.People on e.PersonId equals p.PersonId
where employeesToCollect.Contains(e.PersonId)
select e;
return allDetails;
}
public IEnumerable<Employee> GetEmployeeAndPersonDetailIEnumerable(IEnumerable<int> employeesToCollect)
{
DemoIQueryableEntities db = new DemoIQueryableEntities();
var allDetails = from Employee e in db.Employees
join Person p in db.People on e.PersonId equals p.PersonId
where employeesToCollect.Contains(e.PersonId)
select e;
return allDetails;
}
}
它们含有相同的LINQ创建以下 服务类。它呼吁在program.cs
下面
class Program
{
static void Main(string[] args)
{
SomeServiceClass s= new SomeServiceClass();
var employeesToCollect= new []{0,1,2,3};
//IQueryable execution part
var IQueryableList = s.GetEmployeeAndPersonDetailIQueryable(employeesToCollect).Where(i => i.Gender=="M");
foreach (var emp in IQueryableList)
{
System.Console.WriteLine("ID:{0}, EName:{1},Gender:{2}", emp.PersonId, emp.Person.FirstName, emp.Gender);
}
System.Console.WriteLine("IQueryable contain {0} row in result set", IQueryableList.Count());
//IEnumerable execution part
var IEnumerableList = s.GetEmployeeAndPersonDetailIEnumerable(employeesToCollect).Where(i => i.Gender == "M");
foreach (var emp in IEnumerableList)
{
System.Console.WriteLine("ID:{0}, EName:{1},Gender:{2}", emp.PersonId, emp.Person.FirstName, emp.Gender);
}
System.Console.WriteLine("IEnumerable contain {0} row in result set", IEnumerableList.Count());
Console.ReadKey();
}
}
的output is same for both
明显
ID:1, EName:Ken,Gender:M
ID:3, EName:Roberto,Gender:M
IQueryable contain 2 row in result set
ID:1, EName:Ken,Gender:M
ID:3, EName:Roberto,Gender:M
IEnumerable contain 2 row in result set
所以,问题是什么/哪里是区别定义?它好像没有 有什么区别吧?真!!
让我们在这期间
IQueryable execution part
--IQueryableQuery1
SELECT
[Extent1].[PersonId] AS [PersonId],
[Extent1].[Gender] AS [Gender]
FROM [dbo].[Employee] AS [Extent1]
WHERE ([Extent1].[PersonId] IN (0,1,2,3)) AND (N'M' = [Extent1].[Gender])
--IQueryableQuery2
SELECT
[GroupBy1].[A1] AS [C1]
FROM (SELECT
COUNT(1) AS [A1]
FROM [dbo].[Employee] AS [Extent1]
WHERE ([Extent1].[PersonId] IN (0,1,2,3)) AND (N'M' = [Extent1].[Gender])
) AS [GroupBy1]
IEnumerable execution part
--IEnumerableQuery1
SELECT
[Extent1].[PersonId] AS [PersonId],
[Extent1].[Gender] AS [Gender]
FROM [dbo].[Employee] AS [Extent1]
WHERE [Extent1].[PersonId] IN (0,1,2,3)
--IEnumerableQuery2
SELECT
[Extent1].[PersonId] AS [PersonId],
[Extent1].[Gender] AS [Gender]
FROM [dbo].[Employee] AS [Extent1]
WHERE [Extent1].[PersonId] IN (0,1,2,3)
对实体 framwork 5生成并执行SQL查询来看看
Common script for both execution part
/* these two query will execute for both IQueryable or IEnumerable to get details from Person table
Ignore these two queries here because it has nothing to do with IQueryable vs IEnumerable
--ICommonQuery1
exec sp_executesql N'SELECT
[Extent1].[PersonId] AS [PersonId],
[Extent1].[FirstName] AS [FirstName],
[Extent1].[LastName] AS [LastName]
FROM [dbo].[Person] AS [Extent1]
WHERE [Extent1].[PersonId] = @EntityKeyValue1',N'@EntityKeyValue1 int',@EntityKeyValue1=1
--ICommonQuery2
exec sp_executesql N'SELECT
[Extent1].[PersonId] AS [PersonId],
[Extent1].[FirstName] AS [FirstName],
[Extent1].[LastName] AS [LastName]
FROM [dbo].[Person] AS [Extent1]
WHERE [Extent1].[PersonId] = @EntityKeyValue1',N'@EntityKeyValue1 int',@EntityKeyValue1=3
*/
所以,你现在有几个问题,让我猜那些并尝试回答他们
让我们找到了一些点这里,
所有查询都有一个共同的部分
WHERE [Extent1].[PersonId] IN (0,1,2,3)
为什么呢?因为这两个功能IQueryable<Employee> GetEmployeeAndPersonDetailIQueryable
和SomeServiceClass
IEnumerable<Employee> GetEmployeeAndPersonDetailIEnumerable
包含一个common line in linq queries
where employeesToCollect.Contains(e.PersonId)
比为什么 AND (N'M' = [Extent1].[Gender])
部分在IEnumerable execution part
缺失,而在这两个函数调用我们在program.cs
使用
Where(i => i.Gender == "M")
现在我们在IQueryable
和 之间的差异
什么entity framwork
确实当IQueryable
方法调用,它tooks linq statement written inside the method
并试图找出是否more linq/expression is defind on the resultset
,它收集到的结果中定义的所有的LINQ查询需要获取和constructs more appropriate sql query to execute
。
它提供了许多像好处,
- 仅由SQL Server填充这些行可能是由 整个LINQ查询执行有效
- 有助于通过不选择不必要的行 SQL Server的性能
- 网络成本得到降低
像这里在示例sql服务器只返回到应用程序two rows after IQueryable execution
但returned THREE rows for IEnumerable query
为什么?
在IEnumerable
方法的情况下,entity framework
将linq语句写入方法内部,并在结果需要获取时构造sql查询。 it does not include rest linq part to constructs the sql query
。像这里一样,没有在sql server中对列gender
进行过滤。
但输出是一样的吗?因为'IEnumerable在检索结果后在应用程序级别进一步筛选结果从sql server
SO,应该有人选择什么? 我个人更喜欢将函数结果定义为IQueryable<T>
,因为它具有比'IEnumerable'更好的效果,您可以使用join two or more IQueryable function
这些函数生成更具体的脚本到sql server。
这里的示例中,您可以看到一个IQueryable Query(IQueryableQuery2)
生成比IEnumerable query(IEnumerableQuery2)
更具体的脚本,这在my point of view
中更加可接受。
- 1. 使用IQueryable加入LINQ
- 2. 变换LINQ的IQueryable为分页IQueryable的使用LINQ to NHibernate的
- 3. LINQ IQueryable到IEnumerable
- 4. LINQ IQueryable帮助
- 5. SQL to IQueryable LINQ
- 6. 搜索 - IQueryable Linq
- 7. IQueryable <Entity>在LINQ与嵌套对象IQueryable <DTO>
- 8. 链LINQ的IQueryable,并与存储过程
- 9. IQueryable的Linq到与多个运营商
- 10. LINQ(L2E)与存储过程和IQueryable的
- 11. 如何将LINQ查询与IQueryable组合使用<Guid>
- 12. 在使用LINQ to Entities时返回IQueryable与ObjectQuery
- 13. LINQ;迫使新的{}返回Iqueryable?
- 14. LINQ加入返回的IQueryable
- 15. Linq中的IQueryable,IEnumerable和Lists
- 16. LINQ查询返回的IQueryable
- 17. LINQ和枚举为IQueryable的
- 18. linq to sql ExecuteQuery()as IQueryable
- 19. 字符串LINQ到的IQueryable
- 20. LINQ的IQueryable的变量
- 21. 排序IQueryable结果Linq
- 22. 基于结果使用LINQ替换IQueryable中的所有值使用LINQ
- 23. LINQ:调用存储过程,并与IQueryable的
- 24. 用LINQ返回一个独特的IQueryable?
- 25. IQueryable的使用
- 26. 如何转换的IQueryable <IQueryable的<Page>>到的IQueryable <Page>使用LINQ
- 27. 如何使用.Where与lambda/IQueryable
- 28. 使用与LINQ
- 29. 与使用LINQ
- 30. 存储库模式与WCF休息服务和返回IQUERYABLE使用LINQ到OBJECTS?
“GetQueryableProducts();”的定义在哪里? – Pankaj 2011-12-13 18:28:03
@StackOverflowUser它的目的是任何方法,返回'IQueryable' - 将特定于您的ORM或存储库等 –
2011-12-13 18:58:32
权利。但是你在这个函数调用之后提到了where子句。所以系统仍然不知道过滤器。我的意思是它仍然可以获取产品的所有记录。对? – Pankaj 2011-12-14 04:49:59