构建动态搜索表达式

发布于 2024-11-19 05:24:32 字数 978 浏览 3 评论 0原文

我遇到了麻烦,无法弄清楚似乎很简单的事情,用普通 SQL 可以在 1 分钟内完成,到目前为止已经好几个小时了。情况如下:

  • 我有一个字段,用户可以输入任意数量的单词
  • 我需要构建表达式来查找匹配
  • 假设数据库中有 3 个字段:名字、中间名、姓氏
  • 我需要拆分搜索条目并与
  • 我正在处理的 Silverlight RIA、EF 的
  • 这 3 个字段进行比较再次搜索条目包含未知数量的单词

在我想要完成的任务下,返回类型是强制性的:

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;
}

提前致谢!

I'm in trouble, can't figure out seems a very simple thing that in plain SQL can be done within 1 minute, it's been several hours so far. Here is the situation:

  • I have single field where user may enter as many words as he/she likes
  • I need to build Expression to find match
  • Let's say there are 3 fields in database: firstname, middlename, lastname
  • I need to split the search entry and compare against those 3 fields
  • I'm dealing with Silverlight RIA, EF
  • Once again search entry contains UNKNOWN number of words

Here under what I'm trying to accomplish, return type is mandatory:

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;
}

Thanks in advance!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

我不会写诗 2024-11-26 05:24:32

最简单的事情是使用 Joe Albahari 的 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;

我遗漏了相等性检查,因为“包含”(即 like '%...%')无论如何都会涵盖这种可能性。

不过,我确实必须指出,从业务逻辑的角度来看,您的条件没有任何意义。在什么情况下你想找到名字、姓氏和中间名都包含“John”的人?我怀疑您真正想要的是更像这样的东西:

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

The simplest thing would be to use Joe Albahari's PredicateBuilder to do something like this:

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;

I left out the equality-checks because "Contains" (i.e. like '%...%') will cover that possibility anyway.

I do have to point out, though, that your conditions don't make any sense, from a business logic standpoint. Under what circumstances do you want to find someone whose first, last, and middle name all contain "John"? I suspect what you really want is something more like this:

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;

One final note: Because PredicateBuilder requires you to call .AsExpandable() when you are creating your query, I don't know whether this will work for you. You might have to resort to building your own expressions, which can be somewhat tedious. This can get you started, though:

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);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文