Compose LINQ-to-SQL predicates into a single predicate

后端 未结 2 863
感情败类
感情败类 2021-02-09 23:02

(An earlier question, Recursively (?) compose LINQ predicates into a single predicate, is similar to this but I actually asked the wrong question... the solution there satisfied

相关标签:
2条回答
  • 2021-02-09 23:41

    Normally you would chain invocations of .Where(...). E.g.:

    var a = dataContext.Customers;
    if (kwd1 != null)
        a = a.Where(t => t.Customer.Forenames.Contains(kwd1));
    if (kwd2 != null)
        a = a.Where(t => t.Customer.Forenames.Contains(kwd2));
    // ...
    return a;
    

    LINQ-to-SQL would weld it all back together into a single WHERE clause.

    This doesn't work with OR, however. You could use unions and intersections, but I'm not sure whether LINQ-to-SQL (or SQL Server) is clever enough to fold it back to a single WHERE clause. OTOH, it won't matter if performance doesn't suffer. Anyway, it would look something like this:

    <The type of dataContext.Customers> ff = null, ss = null;
    
    foreach (k in keywords) {
        if (keywords != null) {
            var f = dataContext.Customers.Where(t => t.Customer.Forenames.Contains(k));
            ff = ff == null ? f : ff.Union(f);
    
            var s = dataContext.Customers.Where(t => t.Customer.Surname.Contains(k));
            ss = ss == null ? s : ss.Union(s);
        }
    }
    return ff.Intersect(ss);
    
    0 讨论(0)
  • 2021-02-09 23:59

    You can use the PredicateBuilder class

    IQueryable<Customer> SearchCustomers (params string[] keywords)
    {
      var predicate = PredicateBuilder.False<Customer>();
    
      foreach (string keyword in keywords)
      {
        // Note that you *must* declare a variable inside the loop
        // otherwise all your lambdas end up referencing whatever
        // the value of "keyword" is when they're finally executed.
        string temp = keyword;
        predicate = predicate.Or (p => p.Forenames.Contains (temp));
      }
      return dataContext.Customers.Where (predicate);
    }
    

    (that's actually the example from the PredicateBuilder page, I just adapted it to your case...)


    EDIT:

    Actually I misread your question, and my example above only covers a part of the solution... The following method should do what you want :

    IQueryable<Customer> SearchCustomers (string[] forenameKeyWords, string[] surnameKeywords)
    {
        var predicate = PredicateBuilder.True<Customer>();
    
        var forenamePredicate = PredicateBuilder.False<Customer>();
        foreach (string keyword in forenameKeyWords)
        {
          string temp = keyword;
          forenamePredicate = forenamePredicate.Or (p => p.Forenames.Contains (temp));
        }
        predicate = PredicateBuilder.And(forenamePredicate);
    
        var surnamePredicate = PredicateBuilder.False<Customer>();
        foreach (string keyword in surnameKeyWords)
        {
          string temp = keyword;
          surnamePredicate = surnamePredicate.Or (p => p.Surnames.Contains (temp));
        }
        predicate = PredicateBuilder.And(surnamePredicate);
    
        return dataContext.Customers.Where(predicate);
    }
    

    You can use it like that:

    var query = SearchCustomers(
        new[] { "keyword1", "keyword2" },
        new[] { "keyword3", "keyword4" });
    
    foreach (var Customer in query)
    {
        ...
    }
    
    0 讨论(0)
提交回复
热议问题