2014-10-19 1 views
1

Я строю логику поиска (для приложения MVC), и, если честно, я застрял!Linq to Entities с несколькими связанными объектами и UNIONs

Я потратил несколько дней на создание запроса Linq to Entities для использования проекции. Все было хорошо на поверхности, пока я не посмотрел на сгенерированный оператор SQL под ним. Удушье!

В следующий раз я потратил еще несколько дней, пытаясь избавиться от этих операторов UNION от операторов SQL, пытаясь JOINs, FROMs, INCLUDEs, что угодно, просто даст мне внутренние/левые внешние соединения с связанными объектами, загруженными.

Но я не смог сделать это успешно и все еще застрял на этом этапе.

Некоторые моменты, рассмотреть следующие вопросы:

  • L2E запрос содержит несколько связанных (дочерние) объекты с проекцией (не вопрос здесь, если это не плохой дизайн, т.е. вызывая Союзов)
  • Созданные сводные классы, которые соответствуют анонимные типы, например StudentSummary
  • Сводные классы содержат только несколько столбцов столбцов объекта сущности по соображениям производительности - не нужно возвращать все столбцы при первоначальном поиске
  • Недавно началось использование PredicateBuilder для возврата студентов из поиска, например. студенты-мужчины со специализацией ... Все хорошо в этой области (до сих пор).

Вот что я сделал до сих пор (код изменен, чтобы скрыть собственную собственность - может иметь опечаток):

query = from s in context.Students 
    select new StudentSummary 
    { 
     StudentID = s.StudentID, 
     Title = s.Title, 
     FullName = s.FullName, 
     Qualifications = s.Qualifications, 
     Gender = s.Gender, 
     CampusSummaries = (
        from c in s.Campuses 
        select new CampusSummary 
        { 
         Name = c.Name, 
         LocationSummary = new LocationSummary 
         { 
          State = c.Location.State 
         } 
        }), 
        SpecializationSummaries = (
            from sp in s.StudentSpecializations 
            select new StudentSpecializationSummary 
             { 
              StudentSpecializationID = sp.StudentSpecializationID, 
              SpecializationSummary = new SpecializationSummary 
              { 
               Name = s.Specialization.Name 
              } 
             }), 
        SubSpecializationSummaries = (
            from ssp in s.StudentSubSpecializations 
            select new StudentSubSpecializationSummary 
             { 
              StudentSubSpecializationID = ssp.StudentSubSpecializationID, 
              SubSpecializationSummary = new SubSpecializationSummary 
              { 
               Name = s.SubSpecialization.Name 
              } 
             }) 
}; 

Мои проекционные заявления, как представляется, чтобы сделать Entity Framework генерировать следующие операторы SQL UNION, ниже приведен фрагмент код только (код изменен, чтобы скрыть собственную собственность - может иметь опечатки):

{SELECT 
[UnionAll1].[StudentID] AS [C1], 
[UnionAll1].[StudentID1] AS [C2], 
[UnionAll1].[Title] AS [C3], 
[UnionAll1].[FullName] AS [C4], 
[UnionAll1].[Qualifications] AS [C5], 
[UnionAll1].[Gender] AS [C6], 
[UnionAll1].[C1] AS [C9], 
[UnionAll1].[StudentSpecializationID] AS [C10], 
[UnionAll1].[StudentSpecializationID1] AS [C11], 
[UnionAll1].[StudentSpecializationID2] AS [C12], 
[UnionAll1].[Name] AS [C13], 
[UnionAll1].[C2] AS [C14], 
[UnionAll1].[C3] AS [C15], 
[UnionAll1].[C4] AS [C16], 
[UnionAll1].[C5] AS [C17] 
FROM (SELECT 
    CASE WHEN ([Join1].[StudentSpecializationID] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C1], 
    [Extent1].[StudentID] AS [StudentID], 
    [Extent1].[StudentID] AS [StudentID1], 
    [Extent1].[Title] AS [Title], 
    [Extent1].[FullName] AS [FullName], 
    [Extent1].[Qualifications] AS [Qualifications], 
    [Extent1].[Gender] AS [Gender], 
    [Join1].[StudentSpecializationID] AS [StudentSpecializationID], 
    [Join1].[StudentSpecializationID] AS [StudentSpecializationID1], 
    [Join1].[StudentSpecializationID] AS [StudentSpecializationID2], 
    [Join1].[Name] AS [Name], 
    CAST(NULL AS int) AS [C2], 
    CAST(NULL AS int) AS [C3], 
    CAST(NULL AS int) AS [C4], 
    CAST(NULL AS varchar(1)) AS [C5] 
    FROM [dbo].[Student] AS [Extent1] 
    LEFT OUTER JOIN (SELECT [Extent2].[StudentSpecializationID] AS [StudentSpecializationID], [Extent2].[StudentID] AS [StudentID], [Extent3].[Name] AS [Name] 
     FROM [dbo].[StudentSpecialization] AS [Extent2] 
     INNER JOIN [dbo].[Specialization] AS [Extent3] ON [Extent2].[SpecializationID] = [Extent3].[SpecializationID]) AS [Join1] ON [Extent1].[StudentID] = [Join1].[StudentID] 
UNION ALL 
    SELECT 
    2 AS [C1], 
    [Extent4].[StudentID] AS [StudentID], 
    [Extent4].[StudentID] AS [StudentID1], 
    [Extent4].[Title] AS [Title], 
    [Extent4].[FullName] AS [FullName], 
    [Extent4].[Qualifications] AS [Qualifications], 
    [Extent4].[Gender] AS [Gender], 
    CAST(NULL AS int) AS [C2], 
    CAST(NULL AS int) AS [C3], 
    CAST(NULL AS int) AS [C4], 
    CAST(NULL AS varchar(1)) AS [C5], 
    [Join3].[StudentSubSpecializationID] AS [StudentSubSpecializationID], 
    [Join3].[StudentSubSpecializationID] AS [StudentSubSpecializationID1], 
    [Join3].[StudentSubSpecializationID] AS [StudentSubSpecializationID2], 
    [Join3].[Name] AS [Name] 
    FROM [dbo].[Student] AS [Extent4] 
    INNER JOIN (SELECT [Extent5].[StudentSubSpecializationID] AS [StudentSubSpecializationID], [Extent5].[StudentID] AS [StudentID], [Extent6].[Name] AS [Name] 
     FROM [dbo].[StudentSubSpecialization] AS [Extent5] 
     INNER JOIN [dbo].[SubSpecialization] AS [Extent6] ON [Extent5].[SubSpecializationID] = [Extent6].[SubSpecializationID]) AS [Join3] ON [Extent4].[StudentID] = [Join3].[StudentID]) AS [UnionAll1] 
ORDER BY [UnionAll1].[StudentID1] ASC, [UnionAll1].[C1] ASC} 

Я не уверен, почему союзы используются здесь. Возможно, я плохо использую проекцию. Хотя я заметил, что два или более прогноза включены в ваш оператор L2E, тогда UNIONS появляется в SQL.

Я попытался пойти в другом направлении, удалив выступы, но безуспешно пытался использовать Joins, Froms ... просто не может быть возвращено связанное дочерние объекты.

Я не могу использовать Include, поскольку я использую свои объекты подсчета по соображениям производительности.

Я также спрашиваю, правильно ли я сейчас это сделаю, то есть я иду в правильном направлении, чтобы возвращать вложенные связанные (дочерние) сущности?!?! Возможно, мне следует возвращать плоские результаты, например. Студенты, кампусы, специализации ... объекты находятся на одном уровне, т. Е. Удаляют иерархию.

Вопрос:

Если я построил это с T-SQL Я бы использовать INNER & LEFT OUTER JOIN и вернуть соответствующий ребенок вложенности объектов, а также фильтровать студентов. Это то, чего я пытаюсь достичь с Linq to Entities. Как я могу это сделать? Например. с объединениями, проекцией или любым другим ... (без UNIONs и Cast (NULL) s ...

Оцените любую помощь, даже если она просто указывает мне в правильном направлении, так как я действительно застрял здесь. Благодарю.

ответ

0

Выполняется ли запрос плохо? Если нет, не беспокойтесь о сгенерированном sql. Использование union all может на самом деле быть лучшим способом для этого. Создание одного очень сложного запроса с несколькими объединениями может быть медленнее, чем несколько простых запросов в сочетании с union all

+0

Запрос не работает плохо с небольшим количеством записей, но мне нужно будет выполнить профилирование SQL, чтобы точно узнать. Но хорошая точка re union all vs multiple join - не думала об этом. Прочитайте это, чтобы подтвердить. Спасибо, это помогает. –