如果我在下面的代码示例中使用 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代码完全相同?
答案 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声明实例化泛型,例如,我通常使用var
。 Dictionary<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);