Сегодня я обнаружил, что Entity Framework добавляет ненужный подзапрос к генерируемому SQL. Я начал копать свой код, пытаясь выяснить, откуда он может взяться. А (долго), а потом я точно определил, что вызывает это. Но теперь я более запутан, чем когда я начинал, так как понятия не имею, почему это вызывает это.
По сути, я обнаружил, что в определенных сценариях простое преобразование константы в переменную может изменить SQL, который генерирует Entity Framework. Я сократил все до минимума и упаковал его в небольшое консольное приложение:
using System;
using System.Data.Entity;
using System.Linq;
class Program
{
private static readonly BlogContext _db = new BlogContext();
static void Main(string[] args)
{
const string email = "foo@bar.com";
var comments = from c in _db.Comments
where c.Email == email
select c;
var result = (from p in _db.Posts
join c in comments on p.PostId equals c.PostId
orderby p.Title
select new { p.Title, c.Content });
Console.WriteLine(result);
}
}
public class BlogContext : DbContext
{
public DbSet<Post> Posts { get; set; }
public DbSet<Comment> Comments { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
}
public class Comment
{
public int CommentId { get; set; }
public int PostId { get; set; }
public string Email { get; set; }
public string Content { get; set; }
}
Это показывает следующий вывод, который идеально подходит:
SELECT
[Extent1].[PostId] AS [PostId],
[Extent1].[Title] AS [Title],
[Extent2].[Content] AS [Content]
FROM [dbo].[Posts] AS [Extent1]
INNER JOIN [dbo].[Comments] AS [Extent2] ON [Extent1].[PostId] = [Extent2].[PostId]
WHERE N'foo@bar.com' = [Extent2].[Email]
ORDER BY [Extent1].[Title] ASC
Теперь, если я сделаю email
переменной:
/*const*/ string email = "foo@bar.com";
Вывод радикально меняется:
SELECT
[Project1].[PostId] AS [PostId],
[Project1].[Title] AS [Title],
[Project1].[Content] AS [Content]
FROM ( SELECT
[Extent1].[PostId] AS [PostId],
[Extent1].[Title] AS [Title],
[Extent2].[Content] AS [Content]
FROM [dbo].[Posts] AS [Extent1]
INNER JOIN [dbo].[Comments] AS [Extent2] ON [Extent1].[PostId] = [Extent2].[PostId]
WHERE [Extent2].[Email] = @p__linq__0
) AS [Project1]
ORDER BY [Project1].[Title] ASC
Как примечание, LINQ to SQL, похоже, этого не делает. Я знаю, что, вероятно, можно игнорировать это, поскольку обе команды возвращают одинаковые данные. Но мне очень любопытно, почему это происходит. До сегодняшнего дня у меня всегда было (возможно, ложное?) Впечатление, что всегда безопасно превращать константу в переменную, при условии, что значение остается тем же самым (что в данном случае). Поэтому я должен спросить ...
Почему, казалось бы, незначительное изменение вызывает такую большую разницу в генерируемом SQL?
Обновление:
Просто чтобы прояснить, мой вопрос не в том, чтобы значение email
было жестко закодированным значением в первом запросе и переменной во втором (что имеет смысл в мире). Мой вопрос о том, почему версия переменной приводит к дополнительному подзапросу.
Спасибо!