动态LINQ(Lambda表达式)

1.准备数据实体

        public class Data
        {
            public string AccountNO { get; set; }

            public int Count { get; set; }
        }

创建测试数据

 public static List<Data> GetTestData()
            {
                Data account = new Data
                {
                    AccountNO = "01",
                    Count = 1
                };

                Data account1 = new Data
                {
                    AccountNO = "02",
                    Count = 2
                };

                Data account2 = new Data
                {
                    AccountNO = "03",
                    Count = 3
                };

                Data account3 = new Data
                {
                    AccountNO = "04",
                    Count = 4
                };

                Data account4 = new Data
                {
                    AccountNO = "05",
                    Count = 5
                };
                var rel = new List<Data>
                {
                    account,
                    account1,
                    account2,
                    account3,
                    account4
                };
                return rel;
            }

2.准备查询条件实体

        public class Condition
        {
            [DynamicExpression(Name = "AccountNO", Operator = "Contains")]
            public string Name { get; set; }

            [DynamicExpression(Name = "Count", Operator = ">")]
            public int? Age { get; set; }
        }

数据实体2个字段一个帐号一个年龄大小

查询条件2个字段一个姓名(Name帐号)一个年龄(Age)

为了确保查询字段和数据字段名字保持一直 引用一个自定义特性 在查询条件的每个字段上面标记 

自定义特性包含2个字段一个Name 需要跟数据实体保持一致的名称(注:必须和数据实体的字段对应) Operator 表示运算逻辑符

附自定义实体代码

 [AttributeUsage(AttributeTargets.Property | AttributeTargets.Class, AllowMultiple = true)]
    public class DynamicExpressionAttribute : Attribute
    {
        /// <summary>
        /// 名称
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// 运行符号
        /// </summary>
        public string Operator { get; set; }
    }

从查询条件中提取特效值的扩展类

    public static class CustomAttributeExtension<TAttribute>
        where TAttribute : Attribute
    {
        /// <summary>
        /// Cache Data
        /// </summary>
        private static readonly Dictionary<string, TAttribute> Cache = new Dictionary<string, TAttribute>();

        /// <summary>
        /// 获取CustomAttribute Value
        /// </summary>
        /// <param name="type">实体对象类型</param>
        /// <param name="propertyInfo">实体对象属性信息</param>
        /// <returns>返回Attribute的值,没有则返回null</returns>
        public static TAttribute GetCustomAttributeValue(Type type, PropertyInfo propertyInfo)
        {
            var key = BuildKey(type, propertyInfo);
            if (!Cache.ContainsKey(key))
            {
                CacheAttributeValue(type, propertyInfo);
            }
            return Cache[key];
        }

        /// <summary>
        /// 获取CustomAttribute Value
        /// </summary>
        /// <param name="sourceType">实体对象数据类型</param>
        /// <returns>返回Attribute的值,没有则返回null</returns>
        public static TAttribute GetCustomAttributeValue(Type sourceType)
        {
            var key = BuildKey(sourceType, null);
            if (!Cache.ContainsKey(key))
            {
                CacheAttributeValue(sourceType, null);
            }
            return Cache[key];
        }

        /// <summary>
        /// 获取实体类上的特性
        /// </summary>
        /// <param name="type">实体对象类型</param>
        /// <returns>返回Attribute的值,没有则返回null</returns>
        private static TAttribute GetClassAttributes(Type type)
        {
            var attribute = type.GetCustomAttributes(typeof(TAttribute), false).FirstOrDefault();
            return (TAttribute)attribute;
        }

        /// <summary>
        /// 获取实体属性上的特性
        /// </summary>
        /// <param name="propertyInfo">属性信息</param>
        /// <returns>返回Attribute的值,没有则返回null</returns>
        private static TAttribute GetPropertyAttributes(PropertyInfo propertyInfo)
        {
            var attribute = propertyInfo?.GetCustomAttributes(typeof(TAttribute), false).FirstOrDefault();
            return (TAttribute)attribute;
        }

        /// <summary>
        /// 缓存Attribute Value
        /// <param name="type">实体对象类型</param>
        /// <param name="propertyInfo">实体对象属性信息</param>
        /// </summary>
        private static void CacheAttributeValue(Type type, PropertyInfo propertyInfo)
        {
            var key = BuildKey(type, propertyInfo);
            TAttribute value;
            if (propertyInfo == null)
            {
                value = GetClassAttributes(type);
            }
            else
            {
                value = GetPropertyAttributes(propertyInfo);
            }

            lock (key + "_attributeValueLockKey")
            {
                if (!Cache.ContainsKey(key))
                {
                    Cache[key] = value;
                }
            }
        }

        /// <summary>
        /// 缓存Collection Name Key
        /// <param name="type">type</param>
        /// <param name="propertyInfo">propertyInfo</param>
        /// </summary>
        private static string BuildKey(Type type, PropertyInfo propertyInfo)
        {
            if (string.IsNullOrEmpty(propertyInfo?.Name))
            {
                return type.FullName;
            }
            return type.FullName + "." + propertyInfo.Name;
        }
    }

根据数据和查询条件生成表达式

 public static Func<TResult, bool> GetDynamicExpression<TResult, TCondition>(this IEnumerable<TResult> data, TCondition condtion)
            where TResult : class
            where TCondition : class
        {
            Type tConditionType = typeof(TCondition);
            Type tResultType = typeof(TResult);

            Expression totalExpr = Expression.Constant(true);
            ParameterExpression param = Expression.Parameter(typeof(TResult), "n");
            foreach (PropertyInfo property in tConditionType.GetProperties())
            {
                string key = property.Name;
                object value = property.GetValue(condtion);
                if (value != null && value.ToString() != string.Empty)
                {
                    DynamicExpressionAttribute dynamicExpressionAttribute = CustomAttributeExtension<DynamicExpressionAttribute>.GetCustomAttributeValue(tConditionType, property);

                    //等式左边的值
                    string name = dynamicExpressionAttribute.Name ?? key;
                    Expression left = Expression.Property(param, tResultType.GetProperty(name));
                    //等式右边的值
                    Expression right = Expression.Constant(value);

                    Expression filter;
                    switch (dynamicExpressionAttribute.Operator)
                    {
                        case "!=":
                            filter = Expression.NotEqual(left, right);
                            break;
                        case ">":
                            filter = Expression.GreaterThan(left, right);
                            break;
                        case ">=":
                            filter = Expression.GreaterThanOrEqual(left, right);
                            break;
                        case "<":
                            filter = Expression.LessThan(left, right);
                            break;
                        case "<=":
                            filter = Expression.LessThanOrEqual(left, right);
                            break;
                        case "Contains":
                            filter = Expression.Call(Expression.Property(param, tResultType.GetProperty(name)), typeof(string).GetMethod("Contains", new [] { typeof(string) }), Expression.Constant(value)); ;
                            break;
                        default:
                            filter = Expression.Equal(left, right);
                            break;
                    }
                    totalExpr = Expression.And(filter, totalExpr);
                }
            }
            var predicate = Expression.Lambda(totalExpr, param);
            var dynamic = (Func<TResult, bool>)predicate.Compile();
            return dynamic;
        }

测试 : (查询帐号包含1的数据)

 public static void Test()
            {
                var data = GetTestData();
                var codition = new Condition { Name = "1"};
                var dynamicExpression = GetDynamicExpression(data, codition);
                var query1 = data.Where(dynamicExpression);
            }

 

posted @ 2017-02-06 16:00  刘小吉  阅读(642)  评论(0编辑  收藏  举报