【问题标题】:Advanced Search using Lambda Expression使用 Lambda 表达式的高级搜索
【发布时间】:2015-11-19 02:53:51
【问题描述】:

我想在我的 ASP.NET MVC 应用程序中实现高级搜索,用户可以在其中为产品搜索选择一个或多个条件。

假设我有以下标准:颜色尺寸价格范围

这是我到现在为止的情况

ProductSizeList = db.ProductSizes.Where(ProductSize =>
    (string.IsNullOrEmpty(ProductColorId) || ProductSize.Product.ProductColors.Where(a => a.ColorID == IntColorId).Any())
    ).GroupBy(x => x.ProductID).Select(Grouped => Grouped.FirstOrDefault()).ToList();

ProductColor 表之间存在 多对多 关系,ProductColor 是链接它们的关系。与ProductProductSizeSize 表相同。

代码与SizePrice Range 完美配合。 Color 的问题,因为.Any() 在找到第一个Product 时返回。如果有多个Product,则只返回第一个。

所以,我想知道是否有另一种方法,或者另一种方法可以获取具有指定颜色的所有产品。

我搜索了很多,并且知道我可以动态构建 Where 子句,但我认为这对我的要求来说工作量太大。如果有一个简单的解决方法,我会非常高兴。

编辑

我按照@Jeroen 的建议删除了 working-as-wanted 代码,并留下了我想要修复的代码。

已解决

由于结合了@jason 和@Marlon 的答案,我修复了它。我会将解决方案放在单独的答案中。我只想了解2点:

  • 为什么只有当我基于 Product 进行查询时它才能正常工作?
  • 为什么`.Distinct()`没有做任何事情,我得到了重复的产品。

【问题讨论】:

  • 如果您将代码缩减为您遇到问题的实际 lambda(部分),并包含一些最少的设置代码来重现问题,这将有所帮助。目前,我觉得有很多代码位分散了您遇到的实际问题。
  • 我猜你过滤结果不是通过调用 Any(),而是在这里:Grouped.FirstOrDefault()。顺便说一句,您可以使用谓词直接调用 Any 而不使用 Where 子句: Any(a => a.ColorID == IntColorId)
  • @FireAlkazar 此代码丢弃重复的结果GroupBy(x => x.ProductID).Select(Grouped => Grouped.FirstOrDefault())SizePrice Range,它返回所有结果而不重复。感谢.Any() 部分。

标签: c# lambda


【解决方案1】:

请试试这个。它使用 IQueryable 让您在调用 ToList 时更轻松地构建条件,然后再对数据库执行。

var query = db.ProductSizes.AsQueryable();
if (string.IsNullOrEmpty(ProductColorId) == false)
    query = query.Where(ProductSize => ProductSize.Product.ProductColors.Any(a => a.ColorID == IntColorId))
if (string.IsNullOrEmpty(SizeId) == false)
    query = query.Where(ProductSize => ProductSize.Size.Id == IntSizeId);
if (string.IsNullOrEmpty(From) == false)
    query = query.Where(ProductSize => ProductSize.Price >= DecimalFrom);
if (string.IsNullOrEmpty(To) == false)
    query = query.Where(ProductSize => ProductSize.Price <= DecimalTo);
var ProductSizeList = query
    .Select(ProductSize => ProductSize.ProductID)
    .Distinct()
    .ToList();

【讨论】:

  • 抱歉,我不明白这与我的解决方案有何不同。 .Any() 将在条件满足后返回,并且仅返回第一个产品。
  • 这里的.Any() 仅当颜色链接到一个产品,该产品也链接到您的查询中的 ProductSize 时才返回 true。它尊重符合您其他条件的产品。可能不理想的结果是由于 GroupBy 中的 FirstOrDefault 或原始查询中没有真正分开的 From/To 或因为您有其他产品尺寸与您不期望匹配的产品相关联颜色?如果没有看到您的数据,很难猜出这里出了什么问题,但是这种方法应该没问题。我用过很多次了。
【解决方案2】:

尝试将您的查询基于 Product,而不是 ProductSize:(您没有说,所以我假设 Size 和 Price 在 ProductSize 对象中)。

var query = db.Product.AsQueryable();
if (string.IsNullOrEmpty(ProductColorId) == false)
    query = query.Where(product => product.ProductColors.Where(a => a.ColorID == IntColorId).Any());
if (string.IsNullOrEmpty(SizeId) == false)
    query = query.Where(product => product.Sizes.Where(s => s.Size_Id == IntSizeId));

(...)

var ProductSizeList = query
    .Select(product => product.ProductID)
    .Distinct()
    .ToList();

我更喜欢 Jason W 的方法,而不是将所有内容放在一个查询中,因为在最后一个查询中间的“或”会忽略数据库中的任何索引。

【讨论】:

  • 抱歉,我不明白这与我的解决方案有何不同。 .Any() 将在条件满足后返回,并且仅返回第一个产品。
  • Any 在 Product.Where 中,因此每个产品都会调用它。并且基于 Product 实体的查询,您不需要 Group by。
【解决方案3】:

这对我有用

var query = db.Products.AsQueryable();
if (string.IsNullOrEmpty(ProductColorId) == false)
    query = query.Where(Product => Product.ProductColors.Any(a => a.ColorID == IntColorId));
if (string.IsNullOrEmpty(SizeId) == false)
    query = query.Where(Product => Product.ProductSizes.Any(a => a.SizeID == IntSizeId));
if (string.IsNullOrEmpty(From) == false)
    query = query.Where(Product => Product.ProductSizes.Any(a => a.Price >= DecimalFrom));
if (string.IsNullOrEmpty(To) == false)
    query = query.Where(Product => Product.ProductSizes.Any(a => a.Price <= DecimalTo));
var ProductsList = query
    .Select(ProductSize => ProductSize)
    .GroupBy(x => x.id).Select(Grouped => Grouped.FirstOrDefault())
    .ToList();

我的查询基于Product,并使用GroupBy 而不是Distinct 删除重复结果。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-03-27
    • 1970-01-01
    • 1970-01-01
    • 2018-11-02
    • 2012-05-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多