[英]Dynamic Linq queries for multiple runtime filters
我有一个 winforms 应用程序,它基本上使用实体框架从数据库中加载一堆数据,并将其显示在 gridview 上。
对于这种情况,考虑绑定到 gridview 的实体是这个:
public class Person
{
public string name;
public string sex;
public int age;
}
我想为用户提供选项,通过使用一系列过滤器过滤 gridview 上的结果,他可以在这些过滤器上 select 他想要过滤的列(年龄,性别,姓名),运算符(大于,等于,包含等)和值。
过滤器 class 将是这样的:
public class filter
{
public string column;
public string operator;
public string value;
}
我的问题是:如何通过使用动态创建的 linq 查询将这些过滤器应用于 gridview 上显示的数据?
尝试使用表达式树针对您的数据动态构建 lambda。
这是一个示例实现:
void Main()
{
var fieldName = "LastName";
var value = "test";
var db = new List<Person>() {
new Person() { name = "fred jones", sex = "male", age = 55 },
new Person() { name = "samantha jones", sex = "female", age = 45 },
new Person() { name = "cindy jones", sex = "female", age = 6 }
};
// single query
db.Where( Person.GetFilter("sex", "==", "female").Compile() ).Dump();
// OR example
db.Where(
PredicateBuilder.Or<Person>(
Person.GetFilter("sex", "==", "male"),
Person.GetFilter("age", "<", 50)
).Compile()
).Dump();
}
class Person
{
public string name;
public string sex;
public int age;
public static Expression<Func<Person,bool>> GetFilter<T>(string column, string @operator, T value)
{
var ops = new Dictionary<string, Func<Expression, Expression, Expression>>() {
{ "==", (x,y) => Expression.Equal(x,y) },
{ "<=", (x,y) => Expression.LessThanOrEqual(x,y) },
{ ">=", (x,y) => Expression.GreaterThanOrEqual(x,y) },
{ ">", (x,y) => Expression.GreaterThan(x,y) },
{ "<", (x,y) => Expression.LessThan(x,y) },
};
var param = Expression.Parameter(typeof(Person));
var deref = Expression.PropertyOrField(param, column);
var testval = Expression.Constant(value);
return Expression.Lambda<Func<Person,bool>>(
ops[@operator](deref, testval),
param);
}
}
请注意,我使用 Linqpad 对此进行了测试,因此将 .Dump() 调用替换为适合您的上下文以显示数据的调用。 它需要PredicateBuilder class 来构建 OR 或 AND 语句。 此外,如果错误的类型作为值参数传递(例如,比较年龄时传递的字符串,抛出“InvalidOperationException:二进制运算符 Equal 未为类型 'System.String' 和 'System.Int32' 。”)。
如果有人能告诉我一种更好的方法来处理将运算符的字符串表示形式转换为表达式 class,请告诉我,因为我对上述方法并不满意,但这是我当时能想到的最快的方法.
您可以尝试使用动态 LINQ 库:
或者您可以有条件地将过滤器添加到您的查询中:
var dc = new MyDataContext(); // wrap with using block in production
var query = dc.MyTable.AsQueryable();
if(filter1)
query = query.Where(i=>i.Name.Contains(text));
if(filter2)
query = query.Where(i=>i.Age == age);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.