简体   繁体   中英

Linq search multiple columns with multiple word search term

I am scratching my head how to achieve this

I have a table of products and variations.

Let's say I have a record in my product table with name Sony Monitor

In my variation table, I have a related variation with VariationName of 32"

If I construct my linq as follows:

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

"Sony" would produce a search result. 32" would produce a search result.

Sony 32" would not produce a search result.

What is the best way to achieve this?

EDIT

I have created a ViewModel (ProductSearch) for my search results for ease of use. I added "Matches" as an integer field.

I Concat my product and variation table to get a list of results. The code I am having problems with is as follows:

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();

The error I am receiving is:

The LINQ expression 'x' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'.

Steve,

I think the answer depends, to some extent, on where your data resides. Generally,

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

Should work. If you're using something like LINQ to SQL, or LINQ to Entities, things may start to get a bit messy as some of those technologies don't support string.contains

In the end, you may end up having to do something like:

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

Simple. Try this:

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();

That tries to find as many matches as possible between the search terms and the elements you're searching, giving you the most matches first and down to having at least one match.

You may want to add some .ToLowerInvariant() calls to allow a case-insensitive search.


Try this variation to get the data to load into memory first.

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();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM