简体   繁体   English

使用LINQ过滤多维标准

[英]Using LINQ to Filter Multi Dimensional Criteria

I'm trying to build a search query using LINQ to pass it to Entity Framework utilizing the criteria passed by the user. 我正在尝试使用LINQ构建搜索查询,以使用用户传递的条件将其传递给Entity Framework。 The criteria are two dimensional. 该标准是二维的。

The criteria include "FieldName" and "SearchOperator", for example: 条件包括“ FieldName”和“ SearchOperator”,例如:

FieldName may include " FirstName ", " LastName ", " DateOfBirth ", ...etc FieldName可以包括“ FirstName ”,“ LastName ”,“ DateOfBirth ”等。

SearchOperator may include " Equals ", " BeginsWith ", " EndsWith ", " Greater ", ...etc SearchOperator可以包括“ 等于 ”,“ BeginsWith ”,“ EndsWith ”,“ Greater ”等

As you can see there are too many conditions to be handled. 如您所见,有太多条件需要处理。 What is the best way to implement the code? 实施代码的最佳方法是什么?

My current code looks like this, but I feel like there should be a better way to do it. 我当前的代码看起来像这样,但是我觉得应该有一个更好的方法。

IQueryable<Employee> query = dbContext.Employee;

    switch (FieldName)
    {
        case "FirstName":
            switch (SearchOperator)
            {
                case "Equals":
                    query = query.Where(x => x.FirstName.Equals(SearchValue));
                    break;
                case "BeginsWith":
                    query = query.Where(x => x.FirstName.StartsWith(SearchValue));
                    break;
            }
            break;
        case "LastName":
            switch (SearchOperator)
            {
                case "Equals":
                    query = query.Where(x => x.LastName.Equals(SearchValue));
                    break;
                case "BeginsWith":
                    query = query.Where(x => x.LastName.StartsWith(SearchValue));
                    break;
            }
    }

You can use dynamic linq: 您可以使用动态linq:

check the article: 查看文章:

http://weblogs.asp.net/scottgu/dynamic-linq-part-1-using-the-linq-dynamic-query-library . http://weblogs.asp.net/scottgu/dynamic-linq-part-1-using-the-linq-dynamic-query-library

using dynamic linq you can do like this: 使用动态linq,您可以这样做:

switch (SearchOperator)
                    {
                        case "Equals":
                            query = query.Where(String.Format("{0}={1}",FieldName,SearchValue));
                            break;
                        case "Contains":
                            query = query.Where(String.Format("{0}.Contains({1})",FieldName,arrayOfSearchValues));
                        break;
                        case "StartsWith":
                            query = query.Where(String.Format("{0}.StartsWith({1})",FieldName,SearchValue));
                        break;
                      case "Greater":
                          query = query.Where(String.Format("{0}>{1}",FieldName,SearchValue));
                            break;

                    }   

You can keep you filter dynamicaly in a Dictionary: 您可以在字典中动态过滤:

       IQueryable<Employee> query = dbContext.Employee;

        Dictionary<Tuple<string, string>, Func<Employee, string, bool>> _filter = new Dictionary<Tuple<string, string>, Func<Employee, string, bool>>()
        {
           { new Tuple<string, string>("FirstName","Equals"),   (x,s) => x.FirstName.Equals(s)},
            { new Tuple<string, string>("FirstName","BeginsWith"),   (x,s) => x.FirstName.StartsWith(s)},
             { new Tuple<string, string>("LastName","Equals"),   (x,s) => x.LastName.Equals(s)},
              { new Tuple<string, string>("LastName","BeginsWith"),   (x,s) => x.LastName.StartsWith(s)},

        }; 


        public Employee Get()
        {
             Func<Employee, string, bool> filter = _filter.FirstOrDefault(k => k.Key.Item1 == FieldName && k.Key.Item2 == SearchOperator).Value;

            return query.FirstOrDefault(e => filter(e, SearchValue));
        }

So it is extendable if you need. 因此,如果需要,它可以扩展。

If you do not need high performance or you have small database, you may use IEnumerable to chaining where statements like this: 如果您不需要高性能或数据库较小,则可以使用IEnumerable链接如下所示的where语句:

IEnumerable<Employee> query = dbContext.Employee;
foreach(var searchOperator in searchOperators)
{
     query = query.Where(n=> ....); 
}

otherwise you can try to build expression tree. 否则,您可以尝试构建表达式树。 Take a look here: Expression.Lambda and query generation at runtime, simplest "Where" example 在这里看看: Expression.Lambda和运行时查询生成,最简单的“ Where”示例

For example: 例如:

var employee = Expression.Parameter(typeof(Employee), "employee");
var exprList = new List<BinaryExpression>();
foreach(var searchOperator in searchOperators)
{
  switch(FieldName)
  {
      case "FirstName":
      {   
         var property = Expression.Property(item, "FirstName");

         switch(SearchOperator)
         {
             case "Equal":
                 var equalTo = Expression.Constant(SearchFirstName);
                 var expr = Expression.Equal(property, equalTo);
                 exprList.Add(expr);
                 break;
             case "StartWith":
                 ....
         }


         break;
      }
  }
}
var combined = exprList.Aggregate((n,m)=> Expression.And(n,m));
Expression<Func<Employee, bool>> expr = Expression.Lambda<Func<Item, bool>>(combined, employee);
var output = dbContext.Employee.Where(expr);

( I didn't test code, it may have bugs but I'm convinced that it should look more or less like this) Basicly, it is more efficient because Entity Framework is converting your query to SQL query by traversing Expression>. (我没有测试代码,它可能有错误,但是我坚信它看起来或多或少像这样)基本上,它效率更高,因为Entity Framework通过遍历Expression>将查询转换为SQL查询。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM