【问题标题】:Linq search multiple columns with multiple word search termLinq用多个词搜索词搜索多列
【发布时间】:2021-05-01 19:52:33
【问题描述】:

我正在摸索如何实现这一目标

我有一张产品和变体表。

假设我的产品表中有一条名为 Sony Monitor

的记录

在我的变体表中,我有一个相关变体,其 VariationName 为 32"

如果我按如下方式构造我的 linq:

var productSearch = products.Where(p => p.Name.Contains(searchTerm) || p.Variation.Name.Contains(searchTerm)

“Sony” 会产生搜索结果。 32" 会产生一个搜索结果。

Sony 32" 不会产生搜索结果。

实现这一目标的最佳方法是什么?

编辑

为了便于使用,我为我的搜索结果创建了一个 ViewModel (ProductSearch)。我将“匹配”添加为整数字段。

我合并我的产品和变体表以获取结果列表。我遇到问题的代码如下:

string searchTerm = "Sony 32";
            string[] searchTerms = searchTerm.Split(' ');
            //Concat my two queries (this works fine without the new search code)
            var productSearch = rootProducts.Concat(variableProducts)
                .OrderBy(p => p.Name)
                .Select(p => new ProductSearch()
                {
                    InternalSku = (string)p.InternalSku,
                    ProductId = (int)p.ProductId,
                    ProductVariationId = (int?)p.ProductVariationId,
                    Name = (string)p.Name,
                    ManufacturerSku = (string)p.ManufacturerSku,
                    Ean = (string)p.Ean,
                    ImageUrl = p.ImageUrl,
                    WebDisplay = (bool)p.WebDisplay,
                    VariationName = (string)(p.Name),
                    Matches =
            new[] { p.Name, p.VariationName }
                .SelectMany(x => searchTerms, (x, y) => x.Contains(y))
                .Count(),
                })
                .Skip(skip)
                .Take(take)
                .ToList();

我收到的错误是:

无法翻译 LINQ 表达式“x”。以可翻译的形式重写查询,或通过插入对“AsEnumerable”、“AsAsyncEnumerable”、“ToList”或“ToListAsync”的调用显式切换到客户端评估。

【问题讨论】:

  • 你能指定哪个LINQ:LINQ to SQL / EF 6.x / EF Core 2.0 / 2.1 / 3.x / 5.x?
  • 是的,我使用的是 EF Core 5.0.1

标签: c# sql linq


【解决方案1】:

史蒂夫,

我认为答案在某种程度上取决于您的数据所在的位置。一般来说,

var productSearch = products.Where(p => searchTerm.Contains(p.Name) || searchTerm.Contains(p.Variation.Name))

应该可以。如果您使用的是 LINQ to SQL 或 LINQ to Entities 之类的东西,事情可能会开始变得有些混乱,因为其中一些技术不支持 string.contains

最后,您可能不得不做以下事情:

var productSearch = products.Where(p => searchTerm.Any(x => p.Name.Contains(searchTerm)) || 
    searchTerm.Any(z => p.Variation.Name.Contains(searchTerm)));

【讨论】:

    【解决方案2】:

    简单。试试这个:

    var searchText = "Sony 32";
    var searchTerms = searchText.Split(' ');
    
    var productSearch =
        products
            .Select(p => new
            {
                product = p,
                matches =
                    new[] { p.Name, p.Variation.Name }
                        .SelectMany(x => searchTerms, (x, y) => x.Contains(y))
                        .Count(),
            })
            .Where(x => x.matches >= 1)
            .OrderByDescending(x => x.matches)
            .Select(x => x.product)
            .ToArray();
    

    这会尝试在搜索词和您正在搜索的元素之间找到尽可能多的匹配项,首先为您提供最多的匹配项,然后再提供至少一个匹配项。

    您可能需要添加一些 .ToLowerInvariant() 调用以允许不区分大小写的搜索。


    尝试这种变体,首先将数据加载到内存中。

    var productSearch =
        products
            .Select(p => new { p.Name, Variation = p.Variation.Name })
            .ToArray()
            .Select(p => new
            {
                product = p,
                matches =
                    new[] { p.Name, p.Variation }
                        .SelectMany(x => searchTerms, (x, y) => x.Contains(y))
                        .Count(),
            })
            .Where(x => x.matches >= 1)
            .OrderByDescending(x => x.matches)
            .Select(x => x.product)
            .ToArray();
    

    【讨论】:

    • 是否需要.ToLowerInvariant() 取决于底层数据库及其配置。如果您使用 MS SQL Server 和默认排序规则“SQL_Latin1_General_CP1_CI_AS”,那么它已经不区分大小写(因此名称中包含 CI)
    • 这听起来完全符合我的需要。不幸的是,当我实现它时,我收到一个无法翻译的错误。我正在使用 EF Core。我将用我的完整代码更新我的问题。谢谢
    • 嗨 Enigmativity 你有 SQL 的解决方案吗?我认为 Linq 不可能做到这一点。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-08
    • 1970-01-01
    相关资源
    最近更新 更多