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