简体   繁体   中英

How can I optimise this lambda expression to query using entity framework for each row that contains a list of words?

I have some input, like this: "Steve Brian McFistycuffs Johnson"

and I want to look in my database, and return all records that contain those words in any order.

What I'd do, is something like

var matches = myContext.MyTable.Where( c => c.Name.Contains("Steve") && c.Name.Contains("Brian") && c.Name.Contains("McFistycuffs") && c.Name.Conains("Johnson"));

However I need to do this dynamically, and the number of words could change.

I also want to ensure that whatever I do choose, it doesn't affect the creation of the SQL statement by entity framework, eg. I want to make sure it optimises it as best as possible. That means doing some kind of foreach within the lambda probably won't work because entity framework can't map it to SQL easily.

Any suggestions?

Something like:

static void Main()
{
    string[] words = {"abc", "def"};
    var filter = ContainsAllWords<Person>(x => x.Name, words);
    // same as: x => x.Name.Contains("abc") && x.Name.Contains("def")

    // then:
    var rows = myContext.MyTable.Where(filter);
}
static Expression<Func<T,bool>> ContainsAllWords<T>(
    Expression<Func<T, string>> selector, string[] words)
{
    if (words == null || words.Length == 0) return x => true;

    Expression body = Expression.Call(selector.Body, "Contains", null,
        Expression.Constant(words[0], typeof(string)));
    for (int i = 1; i < words.Length; i++)
    {
        body = Expression.AndAlso(body,
            Expression.Call(selector.Body, "Contains", null,
                Expression.Constant(words[i], typeof(string))));
    }
    return Expression.Lambda<Func<T, bool>>(body, selector.Parameters);
}
var list = new[] { "Brian", "Steve", "Johnson" };
var x = myContext.MyTable.Where(c => list.All(p => c.Name.Contains(p)))
str = "Steve Brian McFistycuffs Johnson"

string[] strParts = str.Split(' ');

myContext.MyTable.Where(c => strParts.All(part => c.Name.contains(part )))
var arr = new string[] {"Steve","Brian","McFistycuffs","Johnson"}; 
var matches = myContext.MyTable.Where(c =>arr.All(ar => ar==c.Name));

Something along the following lines maybe?

string inputFull = "Steve Brian McFistycuffs Johnson";
string[] stringSeparators = new string[] {" "};

var matches = myContext.MyTable;

foreach(string input in inputFull.Split(stringSeparators, StringSplitOptions.None))
{
   matches = matches.Where(c => c.Name.Contains("input"))
}

Edit: using .All() from the answers above would be even better.

Just a wild guess.. how about using regular expressions?

(code not yet tested)

var input = "Steve Brian McFistycuffs Johnson";
var re = new Regex(input.Replace(" ","|"));

var matches = myContext.MyTable.Where( c => re.IsMatch(c.Name));

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