Entity Framework 按字符串过滤数据 sql

Entity Framework filter data by string sql

我正在 table 中存储一些过滤数据。让我说得更清楚:我想将一些 where 子句及其值存储在数据库中,并在我想从数据库中检索数据时使用它们。

例如,考虑一个 people table(实体集)和另一个 table 中的一些过滤器:

"age" , "> 70"
"gender" , "= male"

现在,当我从 people table 检索数据时,我想使用这些过滤器来过滤我的数据。

我知道我可以生成一个 SQL 查询作为字符串并执行它,但是在 EF、LINQ 中还有其他更好的方法吗?

这是一个有趣的问题。首先,确保您对自己诚实:您正在创建一种新的查询语言,这不是一项微不足道的任务(无论您的表达式看起来多么微不足道)。

如果您确定自己没有低估任务,那么您会想看看 LINQ expression trees (reference documentation)。

不幸的是,这是一个相当广泛的主题,我鼓励您学习基础知识并在出现问题时提出更具体的问题。您的目标是解释您的过滤器表达式记录(从您的 table 中获取)并为它们表示的谓词创建一个 LINQ 表达式树。然后您可以像往常一样将树传递给 Where() 调用。

一个解决方案是使用 Dynamic Linq Library ,使用这个库你可以拥有:

filterTable = //some code to retrive it
var whereClause = string.Join(" AND ", filterTable.Select(x=> x.Left + x.Right));
var result = context.People.Where(whereClause).ToList(); 

假设过滤器 table 有列 LeftRight 并且您想按 AND.

加入过滤器

我的建议是在过滤器 table 中包含更多详细信息,例如将运算符与操作数分开并添加一个列来确定连接是 And 还是 OR 以及确定加入这一行的另一行的列。如果你想处理更复杂的查询,比如 (A and B)Or(C and D).

,你需要一个树结构

另一个解决方案是从过滤器 table 构建表达式树。这是一个简单的例子:

var arg = Expression.Parameter(typeof(People));
Expression whereClause;
for(var row in filterTable)
{
     Expression rowClause;
     var left = Expression.PropertyOrField(arg, row.PropertyName);
     //here a type cast is needed for example
     //var right = Expression.Constant(int.Parse(row.Right));
     var right = Expression.Constant(row.Right, left.Member.MemberType);
     switch(row.Operator)
     {
          case "=":
              rowClause = Expression.Equal(left, right);
          break;
          case ">":
              rowClause = Expression.GreaterThan(left, right);
          break;
          case ">=":
              rowClause = Expression.GreaterThanOrEqual(left, right);
          break;
      }
      if(whereClause == null)
      {
          whereClause = rowClause;
      }
      else
      {
          whereClause = Expression.AndAlso(whereClause, rowClause);
      }
}
var lambda = Expression.Lambda<Func<People, bool>>(whereClause, arg);
context.People.Where(lambda);

这是一个非常简单的例子,你应该做很多验证类型转换......为了让它适用于所有类型的查询。

在不知道你的 UI 长什么样的情况下,这里是我在关于 Serialize.Linq

的评论中所说的一个简单示例
    public void QuerySerializeDeserialize()
    {
            var exp = "(User.Age > 7 AND User.FirstName == \"Daniel\") OR User.Age < 10";
            var user = Expression.Parameter(typeof (User), "User");
            var parsExpression = 
                   System.Linq.Dynamic.DynamicExpression.ParseLambda(new[] {user}, null, exp);

            //Convert the Expression to JSON
            var query = e.ToJson();

            //Deserialize JSON back to expression
            var serializer = new ExpressionSerializer(new JsonSerializer());
            var dExp = serializer.DeserializeText(query);

            using (var context = new AppContext())
            {
                var set = context.Set<User>().Where((Expression<Func<User, bool>>) dExp);
            }

   }

使用反射并根据来自表达式的类型调用通用 LINQ 查询,您可能会变得更有趣。这样您就可以避免像我在示例末尾那样强制转换表达式。