LINQ to Entities, соединяющий экземпляр, а не id, генерирует неприятный SQL-код

Может ли кто-нибудь объяснить, почему объединение сущностью, а не id генерирует какой-то действительно уродливый sql, когда на самом деле концептуально это делает то, что вы считаете одним и тем же? например.

По id

from companyDirector in CompanyDirectors
join contactAddress in ContactAddresses
  on companyDirector.ContactAddress.Id equals contactAddress.Id
select new {companyDirector, contactAddress}

Формирует

FROM  [COMPANY] AS [Extent1]
    INNER JOIN [ADDRESS] AS [Extent2] ON [Extent1].[CONTACT_ADDRESS_ID] = [Extent2].[CONTACT_ADDRESS_ID]

В качестве примера

from companyDirector in CompanyDirectors
join contactAddress in ContactAddresses
  on companyDirector.ContactAddress equals contactAddress
select new {companyDirector, contactAddress}

генерирует

FROM  [COMPANY] AS [Extent1]
INNER JOIN [ADDRESS] AS [Extent2] ON  EXISTS (SELECT 
    1 AS [C1]
    FROM    ( SELECT 1 AS X ) AS [SingleRowTable1]
    LEFT OUTER JOIN  (SELECT 
        [Extent3].[CONTACT_ADDRESS_ID] AS [CONTACT_ADDRESS_ID]
        FROM [ADDRESS] AS [Extent3]
        WHERE [Extent1].[CONTACT_ADDRESS_ID] = [Extent3].[CONTACT_ADDRESS_ID] ) AS [Project1] ON 1 = 1
    LEFT OUTER JOIN  (SELECT 
        [Extent4].[CONTACT_ADDRESS_ID] AS [CONTACT_ADDRESS_ID]
        FROM [ADDRESS] AS [Extent4]
        WHERE [Extent1].[CONTACT_ADDRESS_ID] = [Extent4].[CONTACT_ADDRESS_ID] ) AS [Project2] ON 1 = 1
    WHERE [Project1].[CONTACT_ADDRESS_ID] = [Extent2].[CONTACT_ADDRESS_ID]
)

Это выглядит довольно неэффективно для меня, заставляя вас идти по маршруту id. Почему он делает левое соединение дважды, неважно, раз?

Ответы

Ответ 1

В конце концов, для меня EF все еще не хватает зрелости и функций, необходимых для выступления в большом мире. Поэтому я отказался от него в пользу NHibernate, который генерирует просто красивый и оптимизированный SQL.

Ответ 2

Я не могу сказать, что находится в умах или в коде команды ADO.NET. Тем не менее, я вижу две возможные проблемы:

  • Возможно, поле Id в базовой таблице в ContractAddresses или, возможно, только в модели сущности, не может быть определено как первичный ключ. Я несколько сомневаюсь, что это проблема, но стоит дважды проверить.
  • Ключевое слово equals может не иметь хорошего способа сравнить равенство между двумя объектами в соединении. В быстром веб-поиске я не нашел то, что использует equals для сравнения, но это руководство MSDN заставляет меня думать, что задействованы методы equals и GetHashCode (даже если составные клавиши не задействованы). Если вы используете только унаследованный метод object.Equals по умолчанию, поставщик Linq должен каким-то образом определить ссылочное равенство, которое, как я полагаю, может привести к некоторым странным результатам.

Мне нравится решение @Craig Stuntz в его комментарии. Кроме того, вы можете захотеть получить план выполнения для более длинного запроса, чтобы увидеть, действительно ли это так плохо, как выглядит; оптимизатор запросов может сделать лучшую работу, чем указывает код.