2011-09-29 71 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