如何在 .net core 3.1 中订购具有空值的 IQueryable

How to order a IQueryable with null value in .net core 3.1

在我商店的主页上有一个 IQueryable 列表,它会通过不同的过滤器进行更改。 现在,例如,如果折扣价为 null,则 orderBy 时的输出将等于错误。我放了部分代码...

IQueryable<Group> result = _context.Groups
            .Include(c => c.Product)
            .Include(c => c.ProductGroup);

在下面的代码中,使用另一个服务接收输出

switch (getType)
        {
            case "all":
                break;
            case "discountPrice":
                result = IsDiscountedProductsByGroups(result);
                break;
        }

尝试 OrderBy 时出现以下错误。这一步之后,会应用其他过滤器,然后填充一个ViewModel,return值为Tuple。

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;
                    }
            }
        }

已编辑问题:

添加的部分:

评论的小伙伴们好像觉得商品可能不是价格。但我不得不说不。 价格打折但可能开始或结束。 出于这个原因,当这个列表发送到以下服务时,它给出了一个空答案,并且在 orderBy:

时会遇到错误
public IQueryable<Group> IsDiscountedProductsByGroups(IQueryable<Group> groups)
    {

        foreach (var item in groups)
        {
            if (item.Product.PurchasePrice != null)
            {
                if (item.Product.StartDiscountTime != null && item.Product.StartDiscountTime < DateTime.Now)
                {
                    if (item.Product.EndDiscountTime != null && item.Product.EndDiscountTime > DateTime.Now)
                    {
                        listDiscountedProductsByGroup.Append(item);
                    }
                }
            }
        }
        return listDiscountedProductsByGroup;
    }

试试这个:

result = result.OrderByDescending(p => p.Product.PurchasePrice.HasValue)

如果您想包含可能有价格也可能没有价格的产品,并将没有价格的产品视为 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。您的日期比较逻辑中似乎存在一个错误,即折扣开始和结束预计都将小于现在。通常这将是 Start <= now && End >= now.

#3。您的“IsDiscountedProductsByGroups”方法采用 EF IQueryable,并且可能 return 一组实体化实体,这些实体可能是 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
        && x.Product.StartDiscountTime.HasValue 
        && x.Product.StartDiscountTime < now
        && x.Product.EndDiscountTime.HasValue 
        && x.Product.EndDiscountTime > now);
}

... 然后从这里追加适当的 OrderBy。这将确保 IQueryable 仍然是 EF 可查询的。

这假设您只想要具有今天折扣的产品的商品。这看起来有点奇怪,因为我希望产品会有更多的价格历史,或者折扣的想法会被单独跟踪。