Построить динамическое выражение для поиска - PullRequest
0 голосов
/ 07 июля 2011

У меня проблемы, не могу понять, кажется очень простой вещью, что на простом SQL это можно сделать за 1 минуту, пока прошло несколько часов.Вот ситуация:

  • У меня есть одно поле, в котором пользователь может ввести столько слов, сколько ему нравится
  • Мне нужно построить выражение, чтобы найти совпадение
  • Допустим, в базе данных есть 3 поля: имя, отчество, фамилия
  • Мне нужно разделить запись поиска и сравнить с этими 3 полями
  • Я имею дело с Silverlight RIA, EF
  • Еще раз поисковая запись содержит НЕИЗВЕСТНОЕ количество слов

Здесь, в соответствии с тем, что я пытаюсь выполнить, тип возврата обязателен:

public Expression<Func<MyEntity, bool>> GetSearchExpression(string text)
{
    Expression<Func<MyEntity, bool>> result;

    var keywords = text.Trim().Split(" ");
    foreach(var keyword in keywords)
    {
         // TODO: 

         // check whether 'OR' is required (i.e. after second loop)
         // (firstname = 'keyword'
         // AND
         // middlename = 'keyword'
         // AND
         // lastname = 'keyword')
         // OR
         // (firstname like '%keyword%'
         // AND
         // middlename like '%keyword%'
         // AND
         // lastname like '%keyword%')

    }
    return result;
}

Заранее спасибо!

1 Ответ

1 голос
/ 07 июля 2011

Самое простое - использовать PredicateBuilder Джо Албахари , чтобы сделать что-то вроде этого:

var predicate = PredicateBuilder.False<MyEntity>();

foreach (string keyword in keywords)
{
    string temp = keyword;
    predicate = predicate.Or (
        p => p.FirstName.Contains (temp) && 
             p.LastName.Contains (temp) &&
             p.MiddleName.Contains (temp));
}

return predicate;

Я пропустил проверки на равенство, потому что "Contains" (т.е. like '%...%') все равно покроет эту возможность.

Я должен отметить, что ваши условия не имеют никакого смысла с точки зрения бизнес-логики. При каких обстоятельствах вы хотите найти кого-то, чье имя, фамилия и отчество содержат «Джон»? Я подозреваю, что вы действительно хотите что-то вроде этого:

var predicate = PredicateBuilder.True<MyEntity>();

foreach (string keyword in keywords)
{
    string temp = keyword;
    predicate = predicate.And (
        p => p.FirstName.Contains (temp) || 
             p.LastName.Contains (temp) ||
             p.MiddleName.Contains (temp));
}

return predicate;

Последнее замечание: поскольку PredicateBuilder требует, чтобы вы вызывали .AsExpandable() при создании запроса, я не знаю, будет ли это работать для вас. Возможно, вам придется прибегнуть к созданию собственных выражений, что может быть несколько утомительным. Это может помочь вам начать, хотя:

var pParam = Expression.Parameter(typeof(MyEntity), "p");
var predicate = Expression.Constant(true);
foreach (string keyword in keywords)
{
    var keywordExpr = Expression.Constant(keyword);
    // TODO: create an expression to invoke .FirstName getter
    // TODO: create an expression to invoke string.Contains() method
    //TODO: do the same for lastname and middlename

    predicate = Expression.And(predicate, 
        Expression.Or(
            Expression.Or(firstNameContainsKeyword,
                middleNameContainsKeyword),
            lastNameContainsKeyword));
}
return Expression.Lambda<Func<MyEntity, bool>>(predicate, pParam);
...