我正在将一些筛选数据存储在我的表中。让我更清楚地说明一下:我想要在数据库中存储一些where
子句及其值,并在需要从数据库检索数据时使用它们。
例如,考虑一个名为people
的表(实体集)和另一个表中的一些过滤器:
"age" , "> 70"
"gender" , "= male"
现在当我从people
表中检索数据时,我希望使用这些过滤器来过滤我的数据。
我知道我可以生成一个字符串形式的SQL查询并执行它,但是在EF、LINQ中有更好的方法吗?
我正在将一些筛选数据存储在我的表中。让我更清楚地说明一下:我想要在数据库中存储一些where
子句及其值,并在需要从数据库检索数据时使用它们。
例如,考虑一个名为people
的表(实体集)和另一个表中的一些过滤器:
"age" , "> 70"
"gender" , "= male"
现在当我从people
表中检索数据时,我希望使用这些过滤器来过滤我的数据。
我知道我可以生成一个字符串形式的SQL查询并执行它,但是在EF、LINQ中有更好的方法吗?
一种解决方案是使用动态Linq库,使用该库可实现以下功能:
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);
这只是一个非常简化的例子,为了使它适用于所有类型的查询,您需要进行许多验证、类型转换等操作。
如果不知道您的用户界面长什么样,这里有一个简单的例子,讲述我在评论中提到的关于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查询来使它更加复杂。这样,您可以避免像我在示例末尾所做的那样强制转换表达式。