Home > OS >  Multi phrase search in C# LINQ Cannot be translated to SQL
Multi phrase search in C# LINQ Cannot be translated to SQL

Time:10-23

I'm trying to write a semi-advanced LINQ to SQL query to search through my entities in a .NET 6 project. I want to give the user the ability to enter something like "user search a OR alernative lookup b OR seperate query from joe" into a search. After handling the user input, my LINQ query is set up below:

bool isNameSearch = true;
bool isNoteSearch = true;

List<List<string>> _multiSearchList = new()
{
    new List<string>() { "user", "search", "a" },
    new List<string>() { "alternative", "lookup", "b" },
    new List<string>() { "seperate", "query", "from", "joe" }
};


 var _query = (from tblHeader in _DbContext.batches
               where tblHeader.isDeleted != true
               select tblHeader)

_query = _query.Where(x => 
    _multiSearchList.Any(y =>
        y.All(z => 

        (isNameSearch && x.Name.Contains(z)) ||
        (isNoteSearch && x.Note.Contains(z))

        )
    )
);

var _results = await _query.ToListAsync();
var _totalCount = await _query.CountAsync();

The problem is that although this query works with a local collection, it can't be translated to sql. Is there a way to accomplish this?

CodePudding user response:

Since EF Core do not support queries with local collections (exception is Contains), I would suggest using LINQKit which has PredicateBuilder.

Then you can build predicate for your specific case:

bool isNameSearch = true;
bool isNoteSearch = true;

List<List<string>> _multiSearchList = new()
{
    new List<string>() { "user", "search", "a" },
    new List<string>() { "alternative", "lookup", "b" },
    new List<string>() { "seperate", "query", "from", "joe" }
};


var _query = (from tblHeader in _DbContext.batches
               where tblHeader.isDeleted != true
               select tblHeader)

var mainPredicate = PredicateBuilder.New(_query);
foreach (var sentense in _multiSearchList)
[
    var predicate = PredicateBuilder.New(_query);

    foreach(var word in sentense)
    [
        var subPredicate = PredicateBuilder.New(_query);
    
        if (isNameSearch)
            subPredicate = subPredicate.Or(x => x.Name.Contains(word));
        if (isNoteSearch)
            subPredicate = subPredicate.Or(x => x.Note.Contains(word));

        predicate = predicate.And(subPredicate)
    ]

    mainPredicate = mainPredicate.Or(predicate);
]

_query =  _query.Where(mainPredicate);

  • Related