#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
.