对于Entity Framework,Var vs IEnumerable

时间:2011-09-29 04:53:21

标签: linq entity-framework

如果我在下面的代码示例中使用 IEnumerable 而不是 var ,那么SQL只会在执行foreach语句期间生成吗?或者它会在评估Linq语句时执行吗?

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代码完全相同?

3 个答案:

答案 0 :(得分:4)

没有区别。 var只是语法糖。如果您将鼠标悬停在var上,则会看到C#认为您的查询类型为什么。

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

  

从Visual C#3.0开始,在方法范围声明的变量可以具有隐式类型var。隐式类型的局部变量是强类型的,就像您自己声明了类型一样,但编译器确定了类型。 i的以下两个声明在功能上是等效的:

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

<强>更新

正如Omar所提到的,如果您希望立即执行查询(而不是延迟执行),请使用ToList()。这将立即枚举IQueryable / IEnumerable并使用数据库中的实际数据填充列表。

答案 1 :(得分:2)

Linq查询返回IQueryable<>IEnumerable<>,两者的执行都会延迟。

正如DanM所述,无论您使用var还是IEnumerable<>,都取决于您所调用的方法的返回值:如果它是IEnumerable<>IQuerable<>如果你使用.ToList(),它会被推迟,它会马上执行。

何时使用var归结为个人选择/风格。当从代码行和变量名中理解返回值时,或者如果我使用long声明实例化泛型,例如,我通常使用varDictionary<string, Func<Order, object>>

在您的代码中,很明显会返回Customers / Orders的集合,因此我会使用var关键字。同样,这是个人偏好的问题。

答案 2 :(得分: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 query = ...,那么第二行将使用Where扩展(LINQ to Objects)的IEnumerable版本而不是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);