我在我的表中存储了一些过滤数据。让我更清楚一点:我想在数据库中存储一些where
子句及其值,并在我想从数据库中检索数据时使用它们。
例如,在另一个表中考虑一个people
表(实体集)和一些过滤器:
"age" , "> 70"
"gender" , "= male"
现在,当我从people
表中检索数据时,我想让这些过滤器过滤我的数据。
我知道我可以生成一个SQL查询作为字符串并执行它,但在EF,LINQ中还有其他更好的方法吗?
答案 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
加入过滤器。
我的建议是在过滤器表中包含更多详细信息,例如将操作符与操作数分开,并添加一个确定连接为And
或OR
的列和一个确定另一行的列加入这一个。如果要处理更复杂的查询,例如(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 trees(reference 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查询来获得更好的效果。这样你可以避免像我在示例末尾那样强制转换表达式。