Код:
var primeCtr = con.Contractors?.Where(ctr => ctr.Type == "Prime").FirstOrDefault();
if (primeCtr == null)
primeCtr = con.Contractors?.Where(ctr => ctr.Type == "Original Prime").FirstOrDefault();
Объяснение: Если существует подрядчик типа «Прайм», используйте его, иначе используйте «Оригинальный Прайм».
Я мог бы закодировать это, используя ? : выражение, но мне кажется, оно было бы менее эффективно?
var primeCtr = con.Contractors?.Where(ctr => ctr.Type == "Prime").Any() ? con.Contractors?.Where(ctr => ctr.Type == "Prime").FirstOrDefault() : con.Contractors?.Where(ctr => ctr.Type == "Original Prime").FirstOrDefault();
Я думаю, запрос «Prime» будет выполнен дважды?
Просто пытаюсь определить, есть ли более элегантный способ выразить это с помощью EF Core 8? Это мое первое приложение EF Core, и я не использовал старую версию EF уже несколько лет, поэтому она могла заржаветь.





Самый распространенный способ сделать это — заказать по предпочтениям и выбрать первый:
con.Contractors.OrderByDescending(ctr => ctr.Type == "Prime").FirstOrDefault()
Если типов больше, вам придется отфильтровать «Прайм» и «Оригинальный Прайм» (добавьте Where перед заказом).
Порядок нисходящий, потому что тогда тот, где ctr.Type == "Prime" является истинным, всплывает наверх.
Примечание: если con является экземпляром контекста, con.Contractors никогда не имеет значения null и вам не нужен оператор ?.
Это интересная идея. ЕСТЬ еще типы, но они предварительно фильтруются перед этой логикой. Мне нравится этот ответ, но мне любопытно, каково влияние sql.
Вы можете использовать тернарный оператор внутри Where/OrderBy:
var primeCtr = con.Contractors.OrderBy(ctr => ctr.Type == "Prime"
? 1
: ctr.Type == "Original Prime" ? 2
: 3).FirstOrDefault();
Это преобразуется в CASE в SQL: (Не обращайте внимания на имена таблиц/столбцов, это был всего лишь быстрый тест с использованием предыдущей таблицы/объекта)
SELECT [p].[ProjectId], [p].[Name], [p].[Term1], [p].[Term2], [p].[Term3], [p].[TestDateTime]
FROM [Projects] AS [p]
ORDER BY CASE
WHEN [p].[Term1] = N'orange' THEN 1
WHEN [p].[Term1] = N'apple' THEN 2
ELSE 3
END
Вы можете добавить столько значений, сколько необходимо, и даете полный контроль над порядком, не предполагая ни возрастающего, ни убывающего порядка значения типа.
Я мог бы поклясться, что тройка в этом выражении не подойдет. Но это может быть я неправильно помню или старая версия EF. Отлично, потому что именно так я бы сделал это в SQL.
Просто пытаюсь определить, есть ли более элегантный способ выразить это с помощью EF Core 8?
Возможно, не существует «хорошего» способа выразить это в SQL, но есть варианты, если вы хотите сэкономить на обходах, вы можете сделать что-то вроде следующего:
var primeCtr = con.Contractors
.Where(ctr => new []{"Prime", "Original Prime"}.Contains(ctr.Type))
.OrderByDescending(ctr => ctr.Type)
.FirstOrDefault();
Ключевым моментом здесь является порядок: в результате Prime окажется сверху, если таковой имеется.
Чтобы включить больше типов, вы можете использовать тернарный оператор:
var primeCtr = con.Contractors
.Where(ctr => new []{"Prime", "Original Prime", ...}.Contains(ctr.Type))
.OrderBy(ctr => ctr.Type == "Prime"
? 0
: ctr.Type == "Original Prime"
? 1
: ....)
.FirstOrDefault();
В sql оператор CASE WHEN будет работать хорошо
Я не верю, что какой-либо из вариантов
OrderByбудет эффективным, то, что у вас есть, имеет хорошую производительность, хотя и неудобно, если предположить, что индексType