Код:
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