根据属性名称的字符串创建表达式
本文关键字:字符串 创建 表达式 属性 | 更新日期: 2023-09-27 18:27:50
我正在尝试创建一个基于某些JSON的查询,我目前将JSON解析为一组规则,每个规则都包含字段名称、比较类型(=,>等)和要比较的值。
我遇到的问题是将其从该规则中获取到一个IQueryable对象,我想我需要使用反射并以某种方式构建表达式树,但我不确定正确的方法。。。
假设我有:
public class Order : BaseEntity
{
public int OrderID{ get; set; }
}
我的规则是:
public class Rule
{
public string field { get; set; }
public Operations op { get; set; }
public string data { get; set; }
}
运行它我得到:
field = "OrderID"
op = "eq"
data = "123"
我有一种用签名解析它的方法:
public IQueryable<T> FilterObjectSet<T>(IQueryable<T> inputQuery) where T : class
作为这个方法的一部分,我想做:
inputQuery = inputQuery.Where(o => propertyInfo.Name == rule1.data);
这不起作用,因为它基本上只是生成sql"OrderID"="123",这显然是错误的,我需要它从inputQuery中获取与propertyInfo.name同名的列名,并以这种方式构建查询。。。
希望这有意义?有什么建议吗?
编辑:我想我要问的是将一个字符串(因为我可以很简单地根据规则构建一个字符串)转换为一个表达式,也许可以使用Dynamic LINQ?
类似这样的东西:
public static IQueryable<T> FilterObjectSet<T>(IQueryable<T> inputQuery,
Rule rule) where T : class
{
var par = Expression.Parameter(typeof(T));
var prop = Expression.PropertyOrField(par, rule.field);
var propType = prop.Member.MemberType == System.Reflection.MemberTypes.Field ?
((FieldInfo)prop.Member).FieldType :
((PropertyInfo)prop.Member).PropertyType);
// I convert the data that is a string to the "correct" type here
object data2 = Convert.ChangeType(rule.data,
propType,
CultureInfo.InvariantCulture);
var eq = Expression.Equal(prop, Expression.Constant(data2));
var lambda = Expression.Lambda<Func<T, bool>>(eq, par);
return inputQuery.Where(lambda);
}
如果你需要一些解释,你可以问。请注意,这不适用于具有特殊隐式转换的类型(如具有从string
隐式转换而来的MyString
类型)。这是因为Convert.ChangeType
仅使用IConvertible
接口。
data
的空处理可能是其他应该处理的事情。
请注意,我不确定Expression.PropertyOrField
是否由各种IQueryable<T>
引擎(LINQ到SQL和EF)处理。我只在AsQueryable()
引擎上测试过它。如果他们不"接受"它,您必须根据rule.field
的内容将它拆分为Expression.Property
或Expression.Field
。
一个几乎等同的版本,不使用Expression.PropertyOrField
:
public static IQueryable<T> FilterObjectSet<T>(IQueryable<T> inputQuery,
Rule rule) where T : class
{
Type type = typeof(T);
var par = Expression.Parameter(type);
Type fieldPropertyType;
Expression fieldPropertyExpression;
FieldInfo fieldInfo = type.GetField(rule.field);
if (fieldInfo == null)
{
PropertyInfo propertyInfo = type.GetProperty(rule.field);
if (propertyInfo == null)
{
throw new Exception();
}
fieldPropertyType = propertyInfo.PropertyType;
fieldPropertyExpression = Expression.Property(par, propertyInfo);
}
else
{
fieldPropertyType = fieldInfo.FieldType;
fieldPropertyExpression = Expression.Field(par, fieldInfo);
}
object data2 = Convert.ChangeType(rule.data, fieldPropertyType);
var eq = Expression.Equal(fieldPropertyExpression,
Expression.Constant(data2));
var lambda = Expression.Lambda<Func<T, bool>>(eq, par);
return inputQuery.Where(lambda);
}
最后,我使用了在Guthrie的博客上找到的动态Linq库:
http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
使用它,我能够正确地解析并使用我在规则中构建的参数