2011-09-29 53 views
2

如果我使用的IEnumerable的而不是下面的代碼示例VAR,將SQL僅在foreach語句的執行而產生的?或者它會在評估Linq語句時執行?瓦爾VS IEnumerable的,當涉及到實體框架

var query = db.Customers.Where (c => c.Age > 18); 
query = query.Where (c => c.State == "CO"); 
var result = query.Select (c => c.Name); 

foreach (string name in result) // Only now is the query executed! 
    Console.WriteLine (name); 

又如:

IEnumerable<Order> query = db.Orders.Where(o => o.Amount > 1000); 
int orderCount = query.Count(); 

它會更好使用VAR(或IQueryable的),因爲它會被執行SELECT COUNT(*)...當.Count之間的()被執行或它是否與上面顯示的IEnumerable代碼完全相同?

回答

2

通常,在IQueryable上調用GetEnumerator時會生成SQL。

在您的示例中,您可能需要考慮一些細微差別。讓我們把你原來的例子:

var query = db.Customers.Where (c => c.Age > 18); 
query = query.Where (c => c.State == "CO"); 
var result = query.Select (c => c.Name); 

在這種情況下,如果你改變你的第一個查詢到IEnumerable的查詢= ...,那麼第二線將使用Where擴展了IEnumerable版本(LINQ到對象),而不是IQueryable(LINQ to SQL/EF)。因此,當我們開始迭代時,第一個where子句被傳遞給數據庫,但第二個where子句在客戶端執行(因爲它已經被轉換爲IEnumerable)。

你想知道的另一個微妙的項目是以下類型的代碼:

var query = db.OrderBy(c => c.State); 
query = query.Customers.Where(c => c.Age > 18); // Fails: Widening 

在這種情況下,因爲你原來的查詢返回IOrderedQueryable而不是IQueryable的。如果您嘗試將查詢分配給.Where操作的結果,則您試圖擴大返回類型的範圍,編譯器將拒絕執行該擴展。其結果是,你必須明確地指定基準類型,而不是使用VAR:

IQueryable<Customer> query = db.OrderBy(c => c.State); // Is narrowing rather than widening. 
query = query.Customers.Where(c => c.Age > 18); 
+0

你答案的第二部分看起來不正確,或者我錯過了什麼? 'db'不是'DataContext'的一種類型嗎? – Stijn

+0

db是數據上下文,但這裏重要的類型是「查詢」變量的類型。在第一次,它是IOrderedQueryable 第二它只是IQueryable 由於顯式類型聲明。 –

4

這沒有什麼區別。 var只是語法糖。如果您將鼠標懸停在var之上,您將看到C#認爲您的查詢是什麼類型。

http://msdn.microsoft.com/en-us/library/bb383973.aspx

在Visual C#3.0開始,那些在方法範圍聲明的變量可以具有隱式類型變種。一個隱式類型的局部變量是強類型的,就像你自己聲明瞭類型一樣,但是編譯器決定了類型。我的下面兩個聲明在功能上等同:

var i = 10; // implicitly typed 
int i = 10; //explicitly typed 

如果要對其執行查詢操作是SQL不知道做什麼用,如在你的類中定義的方法,那麼你可以使用AsEnumerable()

例如:

var query = db.Customers 
    .Where(c => c.Age > 18) 
    .AsEnumerable() 
    .Select(c => GetCustomerViewModel()); 

//put definition of GetCustomerViewModel() somewhere in the same class 

更新

奧馬爾·提到的,如果你想立即執行查詢(而不是延遲),使用ToList()。這將立即枚舉IQueryable/IEnumerable並用數據庫中的實際數據填充列表。

+0

在第二個代碼示例,不知道的Linq不執行'GetCustomerViewModel'?我只是在LinqPad中沒有'.AsEnumerable()'的情況下測試代碼,它執行得很好。 – Omar

+0

@Omar,您是否使用實體框架DbContext在LinqPad中進行測試? – devuxer

2

Linq查詢返回IQueryable<>IEnumerable<>,兩者的執行都是延遲的。

由於DanM指出,無論是否使用varIEnumerable<>這一切都取決於你調用該方法的返回值:如果它是一個IEnumerable<>IQuerable<>它會被推遲,如果你使用.ToList(),它將立即執行。

何時使用var歸結爲個人選擇/風格。當通過代碼行和變量名來理解返回值時,或者如果我使用長聲明實例化泛型時,我通常使用varDictionary<string, Func<Order, object>>

從您的代碼中,很明顯返回了Customers/Orders的集合,因此我將使用var關鍵字。再次,這是個人喜好的問題。

+0

+1。 'ToList()'好點。我忘了提到這一點。 – devuxer