实体框架按字符串sql过滤数据

时间:2015-08-21 07:59:44

标签: sql sql-server linq entity-framework linq-expressions

我在我的表中存储了一些过滤数据。让我更清楚一点:我想在数据库中存储一些where子句及其值,并在我想从数据库中检索数据时使用它们。

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

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

现在,当我从people表中检索数据时,我想让这些过滤器过滤我的数据。

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

3 个答案:

答案 0 :(得分:8)

一种解决方案是使用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(); 

假设过滤表包含Left列和Right列,并且您希望按AND加入过滤器。

我的建议是在过滤器表中包含更多详细信息,例如将操作符与操作数分开,并添加一个确定连接为AndOR的列和一个确定另一行的列加入这一个。如果要处理更复杂的查询,例如(A and B)Or(C and D)

,则需要树结构

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

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

这是一个非常简化的示例,您应该执行许多类型转换和...的验证,以使其适用于所有类型的查询。

答案 1 :(得分:3)

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

如果您确定自己没有低估任务,那么您需要查看LINQ expression treesreference documentation)。

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

答案 2 :(得分:2)

在不知道您的用户界面的内容的情况下,这是我在关于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查询来获得更好的效果。这样你可以避免像我在示例末尾那样强制转换表达式。