动态生成在运行时谓语 [英] Dynamically generate predicate at runtime

查看:146
本文介绍了动态生成在运行时谓语的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

不知道这是完全有可能的;我发现有关的表达和谓语建设者一些东西,但至今没有什么可以让你运行任意查询不知道他们在前进。

Not sure if this is entirely possible; I've found some stuff about expression and predicate builders, but so far nothing that lets you run arbitrary queries without knowing them in advance.

基本上,我有一个集合从一个大的SQL数据库对象,我建立一个网页(ASP.NET MVC 4)允许用户显示和过滤这些对象。用户将进入查询将在复杂程度而定。让他们进入这些查询的最简单和最巧妙的方法是一样的东西在Visual Studio TFS插件可以让你搜索工作项目的方式:条件,在那里你可以继续添加行的表。您可以选择和或或的连接条件,然后选择一个字段中输入一个值,并选择是否要的东西,做什么或不匹配的:

Basically, I have a collection of objects from a large SQL database, and I'm building a webpage (ASP.NET MVC 4) to allow a user to display and filter these objects. The queries the users will be entering will vary in complexity. The simplest and neatest way to let them enter these queries is something like the way the Visual Studio TFS plugin lets you search work items: a table of conditions, where you can keep adding rows. You select "and" or "or" for the join condition, then select a field, enter a value, and select whether you want things that do or do not match it:

1. show items where [Field] [is|is not] [value]
2.         [and|or] [Field] [is|is not] [value]
3.         [and|or] [Field] [is|is not] [value]
etc...

什么是把这一弄成LINQ十岁上下,我可以在年底粘 .ToList()最简单的方法?我想出了迄今为止唯一的解决方案涉及到一个相当大的和丑陋的开关组与案件相匹配,对各个领域和粘性一个。凡(),但允许用户选择或为条件,那么我最终会做这样的事情:

What's the simplest way to turn that into something LINQ-ish that I can stick a .ToList() on the end of? The only solution I've come up with so far has involved a rather large and ugly switch block with cases to match the various fields and tack on a .Where(), but to allow the user to select "or" for a condition then I end up doing something like this:


  • 虽然条件是AND:

    • 使用大型交换机到外地

    • 匹配
    • 查询= query.Where(ThisField ==值);

    • While condition is AND:
      • use big switch to match the field
      • query = query.Where(ThisField == value);

      • 追加当前结果与临时列表

      • 从全未筛选列表新查询

      • 使用大型交换机到外地匹配

      • 查询= fullList.Where(ThisField ==值);

      • 继续像以前

      • append current results to temporary list
      • new query from full unfiltered list
      • use big switch to match the field
      • query = fullList.Where(ThisField == value);
      • continue as before

      这似乎比我想那么优雅。

      This seems less elegant than I'd like.

      推荐答案

      您可以做到这一点是这样的:

      You can do it like this:

      class Program
      {
          public enum Operator
          {
              And,
              Or
          }
      
          public class Condition
          {
              public Operator Operator { get; set; }
              public string FieldName { get; set; }
              public object Value { get; set; }
          }
      
          public class DatabaseRow
          {
              public int A { get; set; }
              public string B { get; set; }
          }
      
          static void Main(string[] args)
          {
              var conditions = new List<Condition>
              {
                  new Condition { Operator = Operator.And, FieldName = "A", Value = 1 },
                  new Condition { Operator = Operator.And, FieldName = "B", Value = "Asger" },
                  new Condition { Operator = Operator.Or, FieldName = "A", Value = 2 },
              };
      
              var parameter = Expression.Parameter(typeof (DatabaseRow), "x");
              var currentExpr = MakeExpression(conditions.First(), parameter);
              foreach (var condition in conditions.Skip(1))
              {
                  var nextExpr = MakeExpression(condition, parameter);
                  switch (condition.Operator)
                  {
                      case Operator.And:
                          currentExpr = Expression.And(currentExpr, nextExpr);
                          break;
                      case Operator.Or:
                          currentExpr = Expression.Or(currentExpr, nextExpr);
                          break;
                      default:
                          throw new ArgumentOutOfRangeException();
                  }
              }
      
              var predicate = Expression.Lambda<Func<DatabaseRow, bool>>(currentExpr, parameter).Compile();
      
              var input = new[]
              {
                  new DatabaseRow {A = 1, B = "Asger"},
                  new DatabaseRow {A = 2, B = "Hans"},
                  new DatabaseRow {A = 3, B = "Grethe"}
              };
      
              var results = input.Where(predicate).ToList();
          }
      
          static BinaryExpression MakeExpression(Condition condition, ParameterExpression parameter)
          {
              return Expression.Equal(
                  Expression.MakeMemberAccess(parameter, typeof (DatabaseRow).GetMember(condition.FieldName)[0]),
                  Expression.Constant(condition.Value));
          }
      }
      

      这假设你有一个类的模型数据库行用正确的类型。然后,您可以分析您的情况为正则表达式通过上面所示的输入条件的列表,并提供的代码可以转换为表达式树。所产生的表达可以被编译和运行(如图所示)或转换为SQL(只是馅谓词入IQueryable.Where代替)。

      This assumes you have a class as a model of the database row with the correct types. You can then parse your conditions into a list of the typed condition shown above via regex and the provided code can convert that to an expression tree. The resulting expression can either be compiled and run (as shown) or converted to SQL (just stuffing the predicate into the IQueryable.Where instead).

      这篇关于动态生成在运行时谓语的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆