为什么这些用Where条件查找Minimum或Maximum的C# LINQ查询会失败?

r55awzrz  于 2022-12-25  发布在  C#
关注(0)|答案(2)|浏览(167)

为什么这些用Where条件查找最小值或最大值的C# LINQ查询会失败?
我正在处理一个项目,希望对数据库中的列运行查询以查找(a)最大值小于或等于用户输入的最小值,而最小值大于或等于用户输入的最大值。此外,我需要处理其中一个或两个可能都没有返回结果的潜在情况,所以我指定了一个默认值作为返回值。然而,当我运行这段代码时,我在Visual Studio输出窗口中得到了两个隐含的错误:

Exception thrown: 'System.InvalidOperationException' in Microsoft.EntityFrameworkCore.Relational.dll
Exception thrown: 'System.InvalidOperationException' in System.Private.CoreLib.dll

显然,它们表明下面显示的两个查询中的某个问题引起了问题。但是尽管有这些错误,应用程序本身并没有崩溃--它只是安静地停止执行。我最终找到了另一种方法来完成我需要做的事情,但是我留下了一个问题-- * 这两个语句有什么问题?*

fromValue = dbContext.SourceTable.Where(x => x.SourceColumn <= targetFromValue)
                                .Select(x => x.SourceColumn).DefaultIfEmpty(0).Max();

toValue = dbContext.SourceTable.Where(x => x.SourceColumn >= targetToValue)
                              .Select(x => x.SourceColumn).DefaultIfEmpty(99999).Min();
xuo3flqw

xuo3flqw1#

您正在讨论一个数据库,这意味着您正在使用LINQ-To-Entities,而不是LINQ-To-Objects。
DefaultIfEmpty可能无法转换为SQL。
您可以做的是:

toValue = dbContext.SourceTable
    .Where(x => x.SourceColumn >= targetToValue)
    .Min<SourceTableType, int?>(x => x.SourceColumn)

这对您来说可能更好,因为"找不到值"的情况为null,这更容易处理:)

q5lcpyga

q5lcpyga2#

    • 要求1**查找小于或等于用户输入最小值的最大值

为了更容易理解我所说的内容,让我们假设您有一个产品表:

class Product
{
    public int Id {get; set;}
    public string Name {get; set;}
    public decimal Price {get; set;}
    ...
}

你想要的最大价格是不大于€ 10.00(=小于或等于)

decimal limitPrice = 10.00;

decimal largestProductPriceNotLargerThanLimitPrice = dbContext.Products
    .Select(product => product.Price)
    .Where(price => price <= limitPrice)
    .Max();

换句话说:从"产品"表中的每个"产品"中选择其"价格"。从生成的"价格"序列中,仅保留那些小于或等于limitValue的"价格"。从剩余的"价格"序列中,保留最大的一个。
有一个问题:如果没有小于limitPrice的产品价格,则Max不起作用。如果您认为这可能是一个问题,则使用MaxBy而不是Max。如果集合为空,则将返回null。

decimal? largestProductPriceNotLargerThanLimitPriceOrDefault = dbContext.Products
    .Select(product => product.Price)
    .Where(price => price <= limitPrice)
    .MaxBy(price => price);

如果你想在更多的地方使用它,可以考虑为它创建一个扩展方法。如果你不熟悉扩展方法,可以阅读Extension Methods Demystified

public TProperty MaxNotLarger<Tsource, TProperty>(
    this IEnumerable<TSource> source,
    Func<TSource, TProperty> propertySelector,
    TProperty limitValue)
{
    return MaxNotLarger(source, propertySelector, limitValue, null);
    // null: use the default comparer for TProperty
}

public TProperty MaxNotLarger<Tsource, TProperty>(
    this IEnumerable<TSource> source,
    Func<TSource, TProperty> propertySelector,
    TProperty limitValue,
    IComparer<TProperty> comparer)
{
    // TODO: check for correct input parameters
    if (comparer == null) comparer = Comparer<TProperty>.Default;

    return source.Select(sourceItem => propertySelector(sourceItem))
                 .Where(property => comparer.Compare(property, limitValue) <= 0)
                 .Max(comparer);
}

用法:

decimal limitValue = 10.00;
IEnumerable<Product> products = ...

decimal largestProductPriceNotLargerThanLimitValue = products.MaxNotLarger(
    product => product.Price, limitValue);

或者,如果希望最大的Product.id不大于limitValue:

decimal largestProductIdNotLargerThanLimitValue = product.MaxNotLarger(
    product.Product.Id, limitValue);

您可以将其与其他Linq方法结合在一起:

int brandIdPhilips = dbContext.Brands.Where(brand => brand.Name == "Philips")
                                     .Select(brand => brand.Id)
                                     .FirstOrDefault();
var result = dbContext.Products
    .Where(product => product.BrandId = brandIdPhilips)
    .MaxNotLarger(limitValue);

一旦得到这个值,"不小于limitValue的最小值"就很容易了

相关问题