回答
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