#entity-framework #asp.net-core #ef-core-3.1
Вопрос:
На главной странице моего магазина есть список IQueryable, который меняется с помощью различных фильтров. Теперь, например, если цена со скидкой равна нулю, результат на момент заказа будет равен ошибке. Я вставил часть кода …
IQueryable<Group> result = _context.Groups
.Include(c => c.Product)
.Include(c => c.ProductGroup);
В приведенном ниже коде выходные данные получаются с помощью другой службы
switch (getType)
{
case "all":
break;
case "discountPrice":
result = IsDiscountedProductsByGroups(result);
break;
}
Ошибка видна ниже при попытке заказать. После этого шага будут применены другие фильтры, а затем заполнена модель представления, и возвращаемое значение-Кортеж.
if (getType == "discountPrice")
{
switch (orderByType)
{
case "date":
{
result = result.OrderByDescending
(p => p.Product.CreateDate)
.ThenBy(p => p.Product.TireDiameter.Code);
break;
}
case "lowPrice":
{
result = result.OrderBy(p => p.Product.PurchasePrice)
.ThenBy(p => p.Product.TireDiameter.Code);
break;
}
case "highPrice":
{
result = result.OrderByDescending(p => p.Product.PurchasePrice)
.ThenBy(p => p.Product.TireDiameter.Code);
break;
}
}
}
Отредактированный вопрос:
Добавлен раздел:
Друзья, которые прокомментировали это, похоже, подумали, что продукты могут быть не по цене. Но я должен сказать «нет». Цена указана со скидкой, но может начинаться или заканчиваться. По этой причине, когда этот список отправляется в следующую службу, он дает нулевой ответ и при заказе возникнет ошибка:
public IQueryable<Group> IsDiscountedProductsByGroups(IQueryable<Group> groups)
{
foreach (var item in groups)
{
if (item.Product.PurchasePrice != null)
{
if (item.Product.StartDiscountTime != null amp;amp; item.Product.StartDiscountTime < DateTime.Now)
{
if (item.Product.EndDiscountTime != null amp;amp; item.Product.EndDiscountTime > DateTime.Now)
{
listDiscountedProductsByGroup.Append(item);
}
}
}
}
return listDiscountedProductsByGroup;
}
Ответ №1:
Если вы хотите включить продукты, на которые могут быть или не быть цены, и рассматривать товары без цен как 0 (или любое другое значение), попробуйте что-то вроде этого:
result.OrderBy(p => p.Product.PurchasePrice.HasValue ? p.Product.PurchasePrice.Value : 0);
Если вы хотите, чтобы они были помещены в конец списка, вы можете использовать очень большое магическое число вместо «0» выше или лучше:
result.OrderBy(p => p.Product.PurchasePrice.HasValue ? 0 : 1)
.ThenBy(p => p.Product.PurchasePrice.HasValue ? p.Product.PurchasePrice.Value : 0);
Это позволит упорядочить те, у которых есть цена, по цене, а затем переместить те, у которых нет цены, в конец.
Если вы хотите исключить продукты, у которых нет закупочных цен, вам нужно использовать Where
предложение для их фильтрации.
result.Where(p => p.Product.PurchasePrice.HasValue)
.OrderBy(p => p.Product.PurchasePrice.Value);
Обновление: хорошо, основываясь на вашей обновленной реализации, есть пара проблем:
#1. из вашего примера неясно, где объявлена listDiscountedProductsByGroup.
#2. Похоже, в вашей логике сравнения дат есть ошибка, из-за которой ожидается, что как начало, так и конец скидки будут меньше, чем сейчас. Обычно это было бы Начало <= сейчас amp;amp; Конец >= сейчас.
#3. ваш метод «IsDiscountedProductsByGroups» принимает EF IQueryable и потенциально вернет материализованный набор сущностей, которые могут быть IQueryable, но больше не будут выводиться в SQL, а будут обрабатываться в памяти. Это не такая большая проблема, если все, что вы делаете, — это применяете сортировку, но если вы хотите применить любую другую фильтрацию или разбить результаты на страницы с Skip
помощью/ Take
, это нарушает оптимизацию EF для отправки в SQL.
Вместо этого, возможно, это то, что вы ищете:
IQueryable<Group> result = _context.Groups
.Include(c => c.Product)
.Include(c => c.ProductGroup);
if (getType == "discountPrice")
{
var now = DateTime.Now;
result = result.Where(x => x.Product.PurchasePrice != null
amp;amp; x.Product.StartDiscountTime.HasValue
amp;amp; x.Product.StartDiscountTime < now
amp;amp; x.Product.EndDiscountTime.HasValue
amp;amp; x.Product.EndDiscountTime > now);
}
… затем отсюда добавьте соответствующий заказ. Это гарантирует IQueryable
, что EF останется под вопросом.
Это предполагает, что вам нужны только товары, у которых есть Товар со скидкой, под которую сегодня подпадает. Это выглядит немного странно, хотя, поскольку я ожидал бы, что у продукта будет больше истории цен, или идея скидок будет отслеживаться отдельно.
Комментарии:
1. Ваше объяснение было полным, но, к сожалению, вы неправильно поняли мой вопрос. Вопрос был исправлен
2. Я добавил обновление, которое может охватывать сценарий, который, по-видимому, пытается реализовать ваш обновленный пример.
Ответ №2:
Попробуйте это:
result = result.OrderByDescending(p => p.Product.PurchasePrice.HasValue)
Комментарии:
1. Добавлено, но я не видел никаких изменений, и я все еще вижу ошибку