2

我正在尝试基于一些 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 同名的列名并以这种方式构建查询。 ..

希望这是有道理的?有什么建议么?

编辑:我想我要问的是将一个字符串(因为我可以很简单地从规则构建一个)转换为一个表达式,也许使用动态 LINQ?

4

2 回答 2

1

像这样的东西:

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

如果你需要一些解释,你可以问。请注意,这不适用于具有特殊隐式转换的MyString类型(例如具有 from 隐式转换的类型string)。这是因为Convert.ChangeType只使用IConvertible接口。

空值处理data也许是应该处理的其他事情。

请注意,我不确定Expression.PropertyOrField是否由各种IQueryable<T>引擎(LINQ-to-SQL 和 EF)处理。我只用AsQueryable()引擎测试过。如果他们不“接受”它,则必须将其拆分为 a Expression.PropertyExpression.Field取决于是什么rule.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);
}
于 2013-08-15T08:23:31.890 回答
-2

最后,我使用了在 Guthrie 的博客上找到的 Dynamic Linq 库:

http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx

使用它,我能够正确解析并使用我在规则中内置的参数

于 2013-08-15T10:35:58.627 回答