Resharper 的分析是正确的。您可能会多次执行查询。问题出在您的第一行:
IEnumerable<decimal> foo = databaseContext.Foo.Select(f=>f.Key);
在 Entity Framework 中,很少有扩展会实现查询。其中之一是AsEnumerable()
。你的行的右边部分有效地构造了一个IQueryable
但左边的部分是一个IEnumerable
。那时,将通过调用IQueryable
隐式转换为 an ,您的查询将被具体化。IQueryable
AsEnumerable
如果你想推迟查询的执行,左边应该是IQueryable
(var
为了简单起见):
var foo = databaseContext.Foo.Select(f=>f.Key);
另外,我猜这是您的疏忽,但是您foo
可以枚举,decimal
但是您过滤了该Bar
属性。这甚至不会编译。
编辑:我冒昧地修改了您的原始代码(第一部分)以向您展示细分:
// databaseContext.Foo is a (presumably) DbSet<Foo> that implements
// IQueryable<Foo>. Because the variable foo is set to be an IEnumerable<Foo>
// and that IQueryable<Foo> implements IEnumerable<Foo> by calling
// as AsEnumerable(), any further manipulation of the IEnumerable<Foo>
// will be with LINQ to Object and not Linq to SQL (with Entity Framework)
IEnumerable<Foo> foo = databaseContext.Foo;
// Because of the previous point, this will potentially execute the query
if(something)
foo = foo.Where(f=>f.Bar > 5);
// And this will as well
if(somethingElse)
foo = foo.Where(f=>f.Bar > 15);
// And ToList() will definitely execute it.
var json = new JavaScriptSerializer.Serialize(new { fooKeys = foo.Select(f => f.Key).ToList() });
HttpContext.Current.Response.Write(json);
现在,如果你这样做:
// DbSet<Foo> will create an IQueryable<Foo>. An Entity Framework IQueryProvider
// will compile this to an SQL when we want to materialize the query
IQueryable<Foo> foo = databaseContext.Foo;
// Now, if this is hit, it's fine because IQueryable.Where returns an IQueryable
// of the same type. We still live in the
if(something)
foo = foo.Where(f=>f.Bar > 5);
// Same point as before. foo is still an IQueryable<Foo> and the materialization
// is not provoked yet.
if(somethingElse)
foo = foo.Where(f=>f.Bar > 15);
// Here, foo.Select() will return an IQueryable<decimal> (or whatever the type
// of the Foo.Key property is) and then ToList() will get the IEnumerable<decimal>
// version. At that point, any further manipulation is done through Linq to Object
// but the query won't be sent to the database until it is iterated (ie
// the IEnumerable<decimal>.GetEnumerator() is called). The IEnumerable<decimal>
// version of the will be passed to the List<T>(IEnumerable<T>) constructor
// which will iterate through the Enumerable with the GetEnumerator method.
var json = new JavaScriptSerializer.Serialize(new { fooKeys = foo.Select(f => f.Key).ToList() });
HttpContext.Current.Response.Write(json);
如您所见,通过IQueryable
在开始和直到.ToList()
IQueryable