2

我正在尝试为 FilterDescriptor 构建表达式构建器,我从请求中获得在 DB 中执行,因为它仅在内存中执行。我有数千行从数据库中检索(这就是我创建构建器以减少负载的原因)。

//classes
public class Product
{
   public string Name {get;set;}
   public TypeOfProduct {get;set;}
}
public class TypeOfProduct
{
   public string Description {get;set;}
}

//action Read
public ActionResult Read([DataSourceRequest] DataSourceRequest request)
{
    if (request.Filters.Count > 0)
    {
        where = ApplyFilter(request.Filters[0]);
    }
}

// apply the FilterDescriptor to a string 
private static string ApplyFilter(IFilterDescriptor filter)
{
    var filters = string.Empty;
    if (filter is CompositeFilterDescriptor)
    {
        filters += "(";
        var compositeFilterDescriptor = (CompositeFilterDescriptor)filter;
        foreach (IFilterDescriptor childFilter in compositeFilterDescriptor.FilterDescriptors)
        {
            filters += ApplyFilter(childFilter);
            filters += string.Format(" {0} ", compositeFilterDescriptor.LogicalOperator.ToString());
        }
    }
    else
    {
        string filterDescriptor = "{0} {1} {2}";
        var descriptor = (FilterDescriptor)filter;
        if (descriptor.Operator == FilterOperator.IsEqualTo)
        {
            System.Linq.Expressions.Expression<Func<Volume, bool>> func = ExpressionExtension.ConvertStringTo<Volume>(member, "=", descriptor.Value.ToString());
        }

        filters = filterDescriptor;
    }

    filters = filters.EndsWith("And ") == true ? string.Format("{0})", filters.Substring(0, filters.Length - 4)) : filters;
    filters = filters.EndsWith("Or ") == true ? string.Format("{0})", filters.Substring(0, filters.Length - 4)) : filters;

    return filters;
}


// Expression Generator
public static class ExpressionExtension
    {
        public static Expression<Func<T, bool>> ConvertStringTo<T>(string propName, string opr, string value, Expression<Func<T, bool>> expr = null)
        {
            Expression<Func<T, bool>> func = null;
            try
            {
                PropertyInfo prop = null;
                foreach (var x in propName.Split('.'))
                {
                    if (prop == null)
                    {
                        prop = typeof(T).GetProperty(x);
                    }
                    else
                    {
                        prop = prop.PropertyType.GetProperty(x);
                    }
                }
                ParameterExpression tpe = Expression.Parameter(typeof(T));
                Expression left = Expression.Property(tpe, prop);
                Expression right = Expression.Convert(To(prop, value), prop.PropertyType);
                Expression<Func<T, bool>> innerExpr = Expression.Lambda<Func<T, bool>>(ApplyFilter(opr, left, right), tpe);
                if (expr != null)
                {
                    innerExpr = innerExpr.And(expr);
                }
                func = innerExpr;
            }
            catch
            {
            }
            return func;
        }

        public static Expression<Func<T, TResult>> And<T, TResult>(this Expression<Func<T, TResult>> expr1, Expression<Func<T, TResult>> expr2)
        {
            var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
            return Expression.Lambda<Func<T, TResult>>(Expression.AndAlso(expr1.Body, invokedExpr), expr1.Parameters);
        }

        public static Func<T, TResult> ExpressionToFunc<T, TResult>(this Expression<Func<T, TResult>> expr)
        {
            return expr.Compile();
        }

        private static Expression To(PropertyInfo prop, string value)
        {
            object val = Convert.ChangeType(value, ResolveType(prop.PropertyType.ToString()));

            return Expression.Constant(val);
        }

        private static Type ResolveType(String typeName)
        {
            Type type = Type.GetType(typeName);
            if (type == null)
            {
                return null;
            }

            Type underlying = Nullable.GetUnderlyingType(type);

            if (underlying != null)
            {
                type = underlying;
            }
            return type;
        }


        private static BinaryExpression ApplyFilter(string opr, Expression left, Expression right)
        {
            BinaryExpression innerLambda = null;
            switch (opr)
            {
                case "=":
                    innerLambda = Expression.Equal(left, right);
                    break;
            }
            return innerLambda;
        }
    }

问题:如果我的过滤器带有两个字段(“名称”和“描述”),我如何为这两个字段创建连接表达式,因为我需要使用 Product 与 TypeOfProduct 创建连接?

已编辑

return this.Json(this.FactoryDomain.Get().ToDataSourceResult(request, volume => new
            {
                volume.Id,
                volume.ClasseProcessoMarcacao.ClienteId,
                volume.ClasseProcessoMarcacao.Cliente.Pessoa.NomeReduzido,
                volume.ClasseProcessoMarcacao.NomenclaturaPadrao,
                volume.ControleProducaoIdAtual,
                volume.CodigoBarras,
                volume.NumeroCliente,
                volume.NumeroGeral
            }));

这是我将数据返回到网格的示例,但如果我过滤“NomeReduzido”属性,则会引发错误。我决定在我的查询中创建过滤器以直接在数据库中执行。

4

1 回答 1

7

这是一个相当晚的答案,但它可能对其他用户派上用场。您是否尝试过使用 Kendo 的 Expression Builder 来完成此操作,如下所示:

.Where(Kendo.Mvc.ExpressionBuilder.Expression<T>(request.Filters, false).Compile())

我将它与实体框架和/或 Telerik 的数据访问一起用于我的过滤需求。

于 2016-09-13T13:47:38.640 回答