/// <summary>
        /// 构造Contains调用表达式
        /// </summary>
        /// <param name="rule">条件</param>
        /// <param name="parameter">参数</param>
        /// <param name="parameterType">参数类型</param>
        /// <returns>Contains调用表达式</returns>
        private static Expression BuildContainsExpression(JqGridSearchRule rule, Expression parameter, Type parameterType)
        {
            Expression e = null;

            var genMethod = typeof(Queryable).GetMethods()
                            .Single(m1 => m1.Name == "Contains" && m1.GetParameters().Length == 2);

            var jsonArray = JsonConvert.DeserializeObject <string[]>(rule.Data);

            switch (parameterType)
            {
                #region 文字

            case Type ct when ct == typeof(char):
                if (jsonArray.Any(o => o.Length != 1))
                {
                    throw new InvalidOperationException("字符型的候选列表中存在错误的候选项");
                }
                e = CallContains(parameter, jsonArray, str => str[0], genMethod, ct);
                break;

            case Type ct when ct == typeof(string):
                e = CallContains(parameter, jsonArray, str => str, genMethod, ct);
                break;

                #endregion

                #region  符号整数

            case Type ct when ct == typeof(sbyte):
                e = CallContains(parameter, jsonArray, sbyte.Parse, genMethod, ct);
                break;

            case Type ct when ct == typeof(short):
                e = CallContains(parameter, jsonArray, short.Parse, genMethod, ct);
                break;

            case Type ct when ct == typeof(int):
                e = CallContains(parameter, jsonArray, int.Parse, genMethod, ct);
                break;

            case Type ct when ct == typeof(long):
                e = CallContains(parameter, jsonArray, long.Parse, genMethod, ct);
                break;

                #endregion

                #region 无符号整数

            case Type ct when ct == typeof(byte):
                e = CallContains(parameter, jsonArray, byte.Parse, genMethod, ct);
                break;

            case Type ct when ct == typeof(ushort):
                e = CallContains(parameter, jsonArray, ushort.Parse, genMethod, ct);
                break;

            case Type ct when ct == typeof(uint):
                e = CallContains(parameter, jsonArray, uint.Parse, genMethod, ct);
                break;

            case Type ct when ct == typeof(ulong):
                e = CallContains(parameter, jsonArray, ulong.Parse, genMethod, ct);
                break;

                #endregion

                #region 小数

            case Type ct when ct == typeof(float):
                e = CallContains(parameter, jsonArray, float.Parse, genMethod, ct);
                break;

            case Type ct when ct == typeof(double):
                e = CallContains(parameter, jsonArray, double.Parse, genMethod, ct);
                break;

            case Type ct when ct == typeof(decimal):
                e = CallContains(parameter, jsonArray, decimal.Parse, genMethod, ct);
                break;

                #endregion

                #region 其它常用类型

            case Type ct when ct == typeof(DateTime):
                e = CallContains(parameter, jsonArray, DateTime.Parse, genMethod, ct);
                break;

            case Type ct when ct == typeof(DateTimeOffset):
                e = CallContains(parameter, jsonArray, DateTimeOffset.Parse, genMethod, ct);
                break;

            case Type ct when ct == typeof(Guid):
                e = CallContains(parameter, jsonArray, Guid.Parse, genMethod, ct);
                break;

            case Type ct when ct.IsEnum:
                e = CallContains(Expression.Convert(parameter, typeof(object)), jsonArray, enumString => enumString.ToEnumObject(ct), genMethod, ct);
                break;

                #endregion
            }

            return(e);

            MethodCallExpression CallContains <T>(Expression pa, string[] jArray, Func <string, T> selector, MethodInfo genericMethod, Type type)
            {
                var data   = jArray.Select(selector).ToArray().AsQueryable();
                var method = genericMethod.MakeGenericMethod(type);

                return(Expression.Call(null, method, new[] { Expression.Constant(data), pa }));
            }
        }
        /// <summary>
        /// 构造条件表达式
        /// </summary>
        /// <typeparam name="T">搜索的对象类型</typeparam>
        /// <param name="rule">条件</param>
        /// <param name="parameter">参数</param>
        /// <param name="propertyMap">属性映射</param>
        /// <returns>返回bool的条件表达式</returns>
        private static Expression BuildRuleExpression <T>(JqGridSearchRule rule, ParameterExpression parameter, IDictionary <string, string> propertyMap)
        {
            Expression l;

            //如果实体属性名称和前端名称不一致,或者属性是一个自定义类型,需要继续访问其内部属性,使用点号分隔
            if (propertyMap?.ContainsKey(rule.Field) == true)
            {
                var names = propertyMap[rule.Field].Split('.', StringSplitOptions.RemoveEmptyEntries);
                l = Expression.Property(parameter, names[0]);
                foreach (var name in propertyMap[rule.Field].Split('.').Skip(1))
                {
                    l = Expression.Property(l, name);
                }
            }
            else
            {
                l = Expression.Property(parameter, rule.PascalField);
            }

            Expression r = null; //值表达式
            Expression e;        //返回bool的各种比较表达式

            //属于和不属于比较是多值比较,需要调用Contains方法,而不是调用比较操作符
            //为空和不为空的右值为常量null,不需要构造
            var specialRuleOps = new[] { "in", "ni", "nu", "nn" };

            var isGen = false;
            var pt    = typeof(T).GetProperty(rule.PascalField).PropertyType;

            //如果属性类型是可空值类型,取出内部类型
            if (pt.IsDerivedFrom(typeof(Nullable <>)))
            {
                isGen = true;
                pt    = pt.GenericTypeArguments[0];
            }
            //根据属性类型创建要比较的常量值表达式(也就是r)
            if (!specialRuleOps.Contains(rule.Op))
            {
                switch (pt)
                {
                case Type ct when ct == typeof(bool):
                    r = BuildConstantExpression(rule, bool.Parse);
                    break;

                    #region 文字

                case Type ct when ct == typeof(char):
                    r = BuildConstantExpression(rule, str => str[0]);
                    break;

                case Type ct when ct == typeof(string):
                    r = BuildConstantExpression(rule, str => str);
                    break;

                    #endregion

                    #region  符号整数

                case Type ct when ct == typeof(sbyte):
                    r = BuildConstantExpression(rule, sbyte.Parse);
                    break;

                case Type ct when ct == typeof(short):
                    r = BuildConstantExpression(rule, short.Parse);
                    break;

                case Type ct when ct == typeof(int):
                    r = BuildConstantExpression(rule, int.Parse);
                    break;

                case Type ct when ct == typeof(long):
                    r = BuildConstantExpression(rule, long.Parse);
                    break;

                    #endregion

                    #region 无符号整数

                case Type ct when ct == typeof(byte):
                    r = BuildConstantExpression(rule, byte.Parse);
                    break;

                case Type ct when ct == typeof(ushort):
                    r = BuildConstantExpression(rule, ushort.Parse);
                    break;

                case Type ct when ct == typeof(uint):
                    r = BuildConstantExpression(rule, uint.Parse);
                    break;

                case Type ct when ct == typeof(ulong):
                    r = BuildConstantExpression(rule, ulong.Parse);
                    break;

                    #endregion

                    #region 小数

                case Type ct when ct == typeof(float):
                    r = BuildConstantExpression(rule, float.Parse);
                    break;

                case Type ct when ct == typeof(double):
                    r = BuildConstantExpression(rule, double.Parse);
                    break;

                case Type ct when ct == typeof(decimal):
                    r = BuildConstantExpression(rule, decimal.Parse);
                    break;

                    #endregion

                    #region 其它常用类型

                case Type ct when ct == typeof(DateTime):
                    r = BuildConstantExpression(rule, DateTime.Parse);
                    break;

                case Type ct when ct == typeof(DateTimeOffset):
                    r = BuildConstantExpression(rule, DateTimeOffset.Parse);
                    break;

                case Type ct when ct == typeof(Guid):
                    r = BuildConstantExpression(rule, Guid.Parse);
                    break;

                case Type ct when ct.IsEnum:
                    r = Expression.Constant(rule.Data.ToEnumObject(ct));
                    break;

                    #endregion

                default:
                    throw new InvalidOperationException($"不支持创建{pt.FullName}类型的数据表达式");
                }
            }

            if (r != null && pt.IsValueType && isGen)
            {
                var gt = typeof(Nullable <>).MakeGenericType(pt);
                r = Expression.Convert(r, gt);
            }

            switch (rule.Op)
            {
            case "eq":    //等于
                e = Expression.Equal(l, r);
                break;

            case "ne":    //不等于
                e = Expression.NotEqual(l, r);
                break;

            case "lt":    //小于
                e = Expression.LessThan(l, r);
                break;

            case "le":    //小于等于
                e = Expression.LessThanOrEqual(l, r);
                break;

            case "gt":    //大于
                e = Expression.GreaterThan(l, r);
                break;

            case "ge":    //大于等于
                e = Expression.GreaterThanOrEqual(l, r);
                break;

            case "bw":    //开头是(字符串)
                if (pt == typeof(string))
                {
                    e = Expression.Call(l, pt.GetMethod("StartsWith", new[] { typeof(string) }), r);
                }
                else
                {
                    throw new InvalidOperationException($"不支持创建{pt.FullName}类型的开始于表达式");
                }
                break;

            case "bn":    //开头不是(字符串)
                if (pt == typeof(string))
                {
                    e = Expression.Not(Expression.Call(l, pt.GetMethod("StartsWith", new[] { typeof(string) }), r));
                }
                else
                {
                    throw new InvalidOperationException($"不支持创建{pt.FullName}类型的不开始于表达式");
                }
                break;

            case "ew":    //结尾是(字符串)
                if (pt == typeof(string))
                {
                    e = Expression.Call(l, pt.GetMethod("EndsWith", new[] { typeof(string) }), r);
                }
                else
                {
                    throw new InvalidOperationException($"不支持创建{pt.FullName}类型的结束于表达式");
                }
                break;

            case "en":    //结尾不是(字符串)
                if (pt == typeof(string))
                {
                    e = Expression.Not(Expression.Call(l, pt.GetMethod("EndsWith", new[] { typeof(string) }), r));
                }
                else
                {
                    throw new InvalidOperationException($"不支持创建{pt.FullName}类型的不结束于表达式");
                }
                break;

            case "cn":    //包含(字符串)
                if (pt == typeof(string))
                {
                    e = Expression.Call(l, pt.GetMethod("Contains", new[] { typeof(string) }), r);
                }
                else
                {
                    throw new InvalidOperationException($"不支持创建{pt.FullName}类型的包含表达式");
                }
                break;

            case "nc":    //不包含(字符串)
                if (pt == typeof(string))
                {
                    e = Expression.Not(Expression.Call(l, pt.GetMethod("Contains", new[] { typeof(string) }), r));
                }
                else
                {
                    throw new InvalidOperationException($"不支持创建{pt.FullName}类型的包含表达式");
                }
                break;

            case "in":    //属于(是候选值列表之一)
                e = BuildContainsExpression(rule, l, pt);
                break;

            case "ni":    //不属于(不是候选值列表之一)
                e = Expression.Not(BuildContainsExpression(rule, l, pt));
                break;

            case "nu":    //为空
                r = Expression.Constant(null);
                e = Expression.Equal(l, r);
                break;

            case "nn":    //不为空
                r = Expression.Constant(null);
                e = Expression.Not(Expression.Equal(l, r));
                break;

            case "bt":    //区间
                throw new NotImplementedException($"尚未实现创建{rule.Op}类型的比较表达式");

            default:
                throw new InvalidOperationException($"不支持创建{rule.Op}类型的比较表达式");
            }

            return(e);

            Expression BuildConstantExpression <TValue>(JqGridSearchRule jRule, Func <string, TValue> valueConvertor)
            {
                var rv = valueConvertor(jRule.Data);

                return(Expression.Constant(rv));
            }
        }
예제 #3
0
            static Expression BuildConstantExpression <TValue>(JqGridSearchRule jRule, Func <string, TValue> valueConvertor)
            {
                var rv = valueConvertor(jRule.Data);

                return(Expression.Constant(rv));
            }