EF4.2 дополнительное левое внешнее соединение с тем же столом - PullRequest
2 голосов
/ 03 января 2012

Я знаю, что уже есть некоторые вопросы по этому поводу, большинство из которых касаются либо старых проблем, которые были решены, либо нескольких таблиц.Этот вопрос не рассматривается ни в одной из других проблем с «левым внешним соединением», которые я видел, я получаю INNER JOIN и LEFT OUTER JOIN для той же таблицы в том же запросе.

Схема таблицы:

Users: id (PK)
       Name (VARCHAR) 
       ProfileImageUri (VARCHAR)
Locations: id (PK)
LocationBPNTips: id (PK)
                 TipText (VARCHAR)
                 CreatedAt (Datetime)
                 UserId (int) (FK to User.id, navigation property is called User)
                 LocationId (int) (FK to Location.id)

(есть еще, но это не важно :))

В моем сценарии я выполняю запрос к ссылочной таблице через проекцию и получаю дополнительное левое внешнее соединение,это то, что я запускаю ( прокомментированные части не имеют отношения к проблеме, закомментированы для более чистого SQL, EF выполняет сортировку правильно (даже лучше, чем я представлял :))):

LocationBPNTips
     .Where(t => t.LocationId == 33)
     //.OrderByDescending(t => intList.Contains(t.UserId))
     //.ThenByDescending(t => t.CreatedAt)
     .Select(tip => new LocationTipOutput
     {
             CreatedAt = tip.CreatedAt,
             Text = tip.TipText,
             LocationId = tip.LocationId,
             OwnerName = tip.User.Name,
             OwnerPhoto = tip.User.ProfileImageUri
     }).ToList();

И это сгенерированный SQL

SELECT 
[Extent1].[LocationId] AS [LocationId], 
[Extent1].[CreatedAt] AS [CreatedAt], 
[Extent1].[TipText] AS [TipText], 
[Extent2].[Name] AS [Name], 
[Extent3].[ProfileImageUri] AS [ProfileImageUri]
FROM   [dbo].[LocationBPNTips] AS [Extent1]
INNER JOIN [dbo].[Users] AS [Extent2] ON [Extent1].[UserId] = [Extent2].[Id]
LEFT OUTER JOIN [dbo].[Users] AS [Extent3] ON [Extent1].[UserId] = [Extent3].[Id]
WHERE 33 = [Extent1].[LocationId]

Как видите, LEFT OUTER JOIN делается на той же таблице INNER JOIN

Я думаю, что оптимальный кодбыть (обратите внимание, я переименовал Extent3 в Extent2 вручную и добавил комментарий. это не было сгенерировано EF !!) - с моими текущими данными, это работает примерно на 22% быстрее (при сортировке этот% должен быть выше без сортировки), поскольку нет необходимости в дополнительном соединении ..

SELECT 
[Extent1].[LocationId] AS [LocationId], 
[Extent1].[CreatedAt] AS [CreatedAt], 
[Extent1].[TipText] AS [TipText], 
[Extent2].[Name] AS [Name], 
[Extent2].[ProfileImageUri] AS [ProfileImageUri]
FROM   [dbo].[LocationBPNTips] AS [Extent1]
INNER JOIN [dbo].[Users] AS [Extent2] ON [Extent1].[UserId] = [Extent2].[Id]
--LEFT OUTER JOIN [dbo].[Users] AS [Extent3] ON [Extent1].[UserId] = [Extent3].[Id]
WHERE 33 = [Extent1].[LocationId]

РазличныеЗапросы, которые я пробовал (проекция относится к анонимному типу):

LocationBPNTips
     .Where(t => t.LocationId == 33)
     //.OrderByDescending(t => intList.Contains(t.UserId))
     //.ThenByDescending(t => t.CreatedAt)
     .Select(tip => new 
     {
             CreatedAt = tip.CreatedAt,
             Text = tip.TipText,
             LocationId = tip.LocationId,
             OwnerName = tip.User,
             OwnerPhoto = tip.User
     }).ToList()

Вывод SQL был испорчен, он дважды выбирал всю пользовательскую таблицу в том же формате, что и выше, внутренний, затем левый внешний.Я думаю, что теоретически я могу понять, почему это происходит для этого случая, потому что я дважды запрашивал данные - хотя это могло быть сделано в памяти, а не с помощью SQL с дополнительным объединением - но в моем случае я не просилДанные дважды я запрашивал для разных столбцов только один раз.Я выполнил этот тест, чтобы убедиться в совместимости двойного соединения.

Я также попытался запустить:

LocationBPNTips
    .Where(t => t.LocationId == 33)
    .Select(tip => new 
    {
            CreatedAt = tip.CreatedAt,
            Text = tip.TipText,
            LocationId = tip.LocationId,
            OwnerName = tip.User.Name
    }).ToList()

Этот тест вернул чистое единственное внутреннее соединение, как и ожидалось, но это не то, что яя пытаюсь сделать

Так что вопрос : это ошибка?я неправильно использую EF?

1 Ответ

0 голосов
/ 03 января 2012

Я уже видел подобную проблему. Мы можем назвать это ошибкой или функцией. Просто генерация EF-запросов далека от идеала. Команда ADO.NET исправляет некоторые проблемы с каждым основным выпуском. У меня не установлен июньский CTP 2011, чтобы проверить, происходит ли это и в первом превью следующей версии.

Edit:

Согласно этому ответу аналогичная проблема была исправлена ​​в июне CTP 2011.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...