C#在Linq-to-Entities中构建表达式,搜索所有属性'类型

时间:2015-11-30 17:42:17

标签: c# entity-framework linq linq-to-entities expression

我尝试构建动态LINQ到实体查询构建器,以使用属性名称作为字符串返回过滤器表达式,或者检查类型中所有属性的表达式。如果属性是整数,我想检查它是否等于搜索值,否则我想看看属性的字符串值是否包含搜索值。

构建器有两个方法:一个在将属性名称作为字符串和搜索值传递时返回lambda表达式,另一个根据搜索值检查该类型中的所有属性。

对于搜索单个属性,我有以下内容:

    public static Expression<Func<TEntity, bool>> GetFilter<TEntity>(string data, string propertyName)
    {
        var parameter = Expression.Parameter(typeof(TEntity));
        Type t = typeof(TEntity).GetProperty(propertyName).PropertyType;
        var property = Expression.PropertyOrField(parameter, propertyName);
        ConstantExpression constant;
        Expression predicate;



        if (t == typeof(int))
        {
            int temp;
            bool check = int.TryParse(data, out temp);

            if (!check)
            {
                return ((TEntity x) => false);
            }

            constant = Expression.Constant(temp);


            predicate = Expression.Call(property, "Equals", null, constant);
        }
        else
        {
            constant = Expression.Constant(data);
            var toString = Expression.Call(property, "ToString", null);

            predicate = Expression.Call(toString, "Contains", null, constant);



        }


        return Expression.Lambda<Func<TEntity, bool>>(predicate, parameter);

    }

这完美无缺。但是,当尝试使用所有属性执行此操作时,我收到NotSupportedException,指出ToString()无法转换为有效的SQL查询。

要设置表达式,我有一个名为exp的临时表达式,设置它的代码完全相同。然后我连接了#39;通过调用Expression.Or()

来表达式
    public static Expression<Func<TEntity, bool>> GetFilterForAll<TEntity>(string data)
    {

        Type t = typeof(TEntity);
        var parameter = Expression.Parameter(t);

        var properties = from p in t.GetProperties()
                         where p.CanRead && !p.GetGetMethod().IsVirtual && p.Name.ToLower() != "id"
                         select Expression.PropertyOrField(parameter, p.Name);


        Expression predicate = null;

        foreach (var prop in properties)
        {
            ConstantExpression constant;


            Expression exp;

            if (prop.Type == typeof(int))
            {
                int temp;
                bool check = int.TryParse(data, out temp);

                if (!check)
                {
                    continue;
                }

                constant = Expression.Constant(temp);


                exp = Expression.Call(prop, "Equals", null, constant);
            }
            else
            {
                constant = Expression.Constant(data);
                var toString = Expression.Call(prop, "ToString", null);

                exp = Expression.Call(toString, "Contains", null, constant);


            }



            if (predicate == null)
            {
                predicate = exp;
            }
            else
            {
                predicate = Expression.Or(predicate, exp);
            }

        }

        if (predicate == null) return null;

        return Expression.Lambda<Func<TEntity, bool>>(predicate, parameter);

    }

我知道我在某个地方出错了,特别是因为今天已经学到了所有这些,我怀疑我是如何做到的,或者是&#39;表达式。

1 个答案:

答案 0 :(得分:1)

我在没有 等于 的情况下执行此操作,因为不在范围内我将需要创建一些attr或flag来设置将过滤的道具 完全 可能 ,我只是进入导航的1级深度,所以也许这可以帮助您理解:

private static readonly MethodInfo ToStringMethod = typeof(object).GetMethod("ToString");
private static readonly MethodInfo StringContainsMethod = typeof(string).GetMethod("Contains");

public static Expression<Func<T, bool>> BuildFilterPredicate<T>(string q)
{
    var query = Expression.Constant(q);
    var type = typeof(T);
    var lambdaParam = Expression.Parameter(type);
    var predicates = type.GetProperties().SelectMany(p => PredicateContainsBuilder(lambdaParam, p, query)).ToList();
    Expression body = predicates[0];
    body = predicates.Skip(1).Aggregate(body, Expression.OrElse);
    return Expression.Lambda<Func<T, bool>>(body, lambdaParam);
}

private static IEnumerable<MethodCallExpression> PredicateContainsBuilder(Expression lambdaParam, PropertyInfo prop, Expression query)
{

    if (prop.PropertyType.IsClass)
        return new List<MethodCallExpression> { Expression.Call(Expression.Call(Expression.Property(lambdaParam, prop), ToStringMethod), StringContainsMethod, query) };

    var properties = prop.PropertyType.GetProperties();
    return properties.Select(p => Expression.Call(Expression.Call(Expression.Property(lambdaParam, p), ToStringMethod), StringContainsMethod, query)).ToList();
}

尝试使用OrElse代替Or