Как упорядочить по объединенным значениям в Entity Framework / Linq?

#c# #sql-server #linq

#c# #sql-сервер #linq

Вопрос:

У меня ситуация, когда записи в родительской таблице (Record) могут иметь одну из двух связанных записей в дочерних таблицах (PhysicalPerson и Company). Один из столбцов всегда будет пустым.

При отображении записей в сетке пользовательского интерфейса пользователь должен видеть только одно из двух имен в столбце OwnerName, и пользователь должен иметь возможность сортировать столбец OwnerName, не зная, принадлежит ли имя владельца для какой-либо записи компании или физическому лицу.

Чтобы избежать денормализации данных, копирования и сохранения столбца Name, я попытался сделать все это в запросе Linq.

В принципе, желаемое order by выражение SQL, которое работает, должно выглядеть следующим образом:

 ORDER BY CONCAT(Record.PhysicalPerson.Name,
Record.PhysicalPerson.Surname,
Record.Company.Name)

  

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

Итак, я попытался реализовать это в Linq:

 query = query.OrderBy(x => x.PhysicalPerson.Name   
                                        x.PhysicalPerson.Surname  
                                        x.Company.Name);

  

но результирующий запрос, сгенерированный Entity Framework, выглядит следующим образом:

 [Extent4].[Name]   [Extent6].[Surname]   [Extent8].[Name] AS [C1]
...
ORDER BY [Project1].[C1] ASC
...
  

Очевидно, что не работает в качестве замены CONCAT в SQL.

Есть ли какой-либо способ заставить EntityFramework генерировать CONCAT вместо для конкатенации строк в OrderBy?

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

Комментарии:

1. Я обычно придерживаюсь принципа, позволяющего ядру базы данных работать с ворчанием, и позволяю вашему C # делать как можно меньше, чтобы получить желаемый результат. Возможно, я предвзят из-за опыта SQL DBA, но на ум приходит мысль «правильный инструмент для правильной работы».

2. Вы можете использовать String.Concat(x.PhysicalPerson.Name ?? "", x.PhysicalPerson.Surname ?? "", x.Company.Name ?? "") .

3. @NetMage Спасибо, теперь он генерирует запрос, подобный этому: CASE WHEN ([Extent4].[Name] IS NULL) THEN N'' ELSE [Extent6].[Name] END CASE WHEN ([Extent8].[Surname] IS NULL) THEN N'' ELSE [Extent10].[Surname] END CASE WHEN ([Extent12].[Name] IS NULL) THEN N'' ELSE [Extent14].[Name] END AS [C1] и он работает правильно. Я думаю, проверка NULL была решающей здесь, чтобы получить тот же результат, что и с CONCAT помощью . Не стесняйтесь добавлять свой комментарий к новому ответу, и я отмечу его как принятый.

Ответ №1:

Попробуйте это:

 query = query.OrderBy(x => x.PhysicalPerson.Name).ThenBy(x.PhysicalPerson.Surname).ThenBy(x.Company.Name);
  

Комментарии:

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

2. Что, когда вы заменяете «x.Company.Name «by «x.Компания. Name == null ? строка. Пусто: x.Company.Name «?

Ответ №2:

К сожалению, трансляторы LINQ для SQL / EF не используются CONCAT для перевода конкатенации строк, что несовместимо с тем, как другие переводы ожидают, что SQL будет автоматически обрабатывать null (или, возможно, в определении SQL as, отличном от CONCAT , заключается проблема). В любом случае, вы можете сделать нулевой тест явным, например:

 query = query.OrderBy(x => String.Concat(x.PhysicalPerson.Name ?? "", x.PhysicalPerson.Surname ?? "", x.Company.Name ?? ""));
  

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