Я столкнулся со странным поведением в Entity Framework 4.3.1. В приведенном ниже примере я создаю простую модель и выполняю два разных запроса, которые, по моему мнению, должны быть эквивалентны. Первый использует оператор All
, а другой использует комбинацию Where
и Any
для достижения того же результата.
Первый запрос выглядит так:
var result = db.Projects
.Where(p => p.Id == 1)
.All(p => db.Operations.Any(o => o.Name == "foo" && o.Project.Id == p.Id));
При выполнении он вызывает следующие два запроса к базе данных, где «дополнительный» выглядит так:
SELECT
1 AS [C1],
[Extent1].[Id] AS [Id],
[Extent1].[Name] AS [Name],
[Extent1].[Project_Id] AS [Project_Id]
FROM [dbo].[Operations] AS [Extent1]
Второй запрос выглядит так:
var result = !db.Projects // Single query
.Where(p => p.Id == 1)
.Where(p => !db.Operations.Any(
o => o.Name == "foo" && o.Project.Id == p.Id))
.Any();
Это выполняет один запрос, но более сложный.
Я не знаю, почему первая версия вызывает два запроса. Это приводило к ошибкам в моем коде, которые я не смог воспроизвести в небольшом примере.
Мой вопрос: Почему первый запрос выполняет два запроса к базе данных? Это ошибка, о которой я должен сообщить?
Полный код ниже:
using System.Data.Entity;
using System.Linq;
namespace EFTest {
class Program {
static void Main(string[] args) {
var connStr = @"Data Source=.\SQLServer; Initial catalog = EFTest;"
+ " Integrated Security=True; MultipleActiveResultSets=True";
using (var db = new MyDbContext(connStr)) {
var result = db.Projects // Two queries!
.Where(p => p.Id == 1)
.All(p => db.Operations.Any(
o => o.Name == "foo" && o.Project.Id == p.Id));
}
using (var db = new MyDbContext(connStr)) {
var result = !db.Projects // Single query
.Where(p => p.Id == 1)
.Where(p => !db.Operations.Any(
o => o.Name == "foo" && o.Project.Id == p.Id))
.Any();
}
}
}
public class Project {
public long Id { get; set; }
public string Name { get; set; }
}
public class Operation {
public long Id { get; set; }
public string Name { get; set; }
public virtual Project Project { get; set; }
}
public class MyDbContext : DbContext
{
public virtual IDbSet<Project> Projects { get; set; }
public virtual IDbSet<Operation> Operations { get; set; }
public MyDbContext(string nameOrConnectionString)
: base(nameOrConnectionString) { }
}
}