首先,我有个List<PoFileModel> list = PoService.GetAll(t=>xxxxxx);
还有个返回Expression<Func<PoFileModel, bool>>对象的PermissionExpression方法。
public static class PredicateExtensions { public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> exprLeft, Expression<Func<T, bool>> exprRight) { var invokedExpr = Expression.Invoke(exprRight, exprLeft.Parameters); return Expression.Lambda<Func<T, bool>>(Expression.OrElse(exprLeft.Body, invokedExpr), exprLeft.Parameters); } public static Expression<Func<PoFileModel, bool>> PermissionExpression(this Expression<Func<PoFileModel, bool>> predicate, string value, Func<PoFileModel, string> fieldFunc) { if (!string.IsNullOrEmpty(value) && value.Contains(";")) { string[] items = value.Split(';'); Expression<Func<PoFileModel, bool>> predicate1 = o => fieldFunc(o).Contains(items[0]); for (int i = 1; i < items.Length; i++) { int j = i; predicate1 = predicate1.Or(o => fieldFunc(o).Contains(items[j])); } predicate = predicate.Or(predicate1); } else { predicate = predicate.Or(o => fieldFunc(o).Contains(value)); } return predicate; } }
这是方法调用:
IQueryable<PoFileModel> newList = list.AsQueryable(); Expression<Func<PoFileModel, bool>> predicate = i => 1 == 0; if (groups.Any(t => t.Name == Groups.UniqloVendor.ToString())) { predicate = PermissionExpression(predicate, user.VendorCode, o => o.VendorCode); } if (groups.Any(t => t.Name == Groups.UniqloBranchFactory.ToString())) { predicate = PermissionExpression(predicate, user.BranchFactoryCode, o => o.BranchFactoryCode); } if (groups.Any(t => t.Name == Groups.UniqloManagementFactory.ToString())) { predicate = PermissionExpression(predicate, user.ManagementFactoryCode, o => o.ManagementFactoryCode); } return newList.Where(predicate).ToList();
这里有个问题:
当这个list赋给newList对象前没有ToList等调用时,实际上它只是一个表达式(延时执行),也就是说,最终会到数据库执行查询。
一旦执行这个newList.Where(predicate).ToList()语句,它会报错,提示类似"无法识别fieldFunc"等错误。
当这个list赋给newList对象时调用了ToList方法,那么,数据已经在本地。执行这个newList.Where(predicate).ToList()语句,会返回正确结果。
我想要效果的是:
如何在PermissionExpression内部方法里根据fieldFunc生成动态属性的表达式?
public static class ExpressionExtensions { public static IQueryable<T> WhereIf<T>(this IQueryable<T> list, Expression<Func<T, bool>> expr) { if (expr == null) { return list; } return list.Where(expr); } public static Expression<Func<T, bool>> OrContains<T>(this Expression<Func<T, string>> fieldFunc, string value) { ParameterExpression parameter = fieldFunc.Parameters.First(); MemberExpression member = fieldFunc.Body as MemberExpression; MethodInfo method = typeof(string).GetMethod("Contains", new[] { typeof(string) }); Expression exprLeft; if (!string.IsNullOrEmpty(value) && value.Contains(";")) { var items = value.Split(';'); exprLeft = null; foreach (var item in items) { ConstantExpression constant = Expression.Constant(item, typeof(string)); MethodCallExpression exprRight = Expression.Call(member, method, constant); if (exprLeft == null) { exprLeft = exprRight; } else { exprLeft = Expression.Or(exprLeft, exprRight); } } if (exprLeft == null) { Expression<Func<T, bool>> defaultFilter = o => true; exprLeft = defaultFilter; } } else { ConstantExpression constant = Expression.Constant(value, typeof(string)); exprLeft = Expression.Call(member, method, constant); } Expression<Func<T, bool>> expr = Expression.Lambda<Func<T, bool>>(exprLeft, parameter); return expr; } public static Expression<Func<T, bool>> OrContainsIf<T>(this Expression<Func<T, bool>> expr, Expression<Func<T, string>> fieldFunc, string value) { if (expr == null) { expr = OrContains(fieldFunc, value); } else { expr = expr.Or(OrContains(fieldFunc, value)); } return expr; } }
Expression<Func<PoFileModel, bool>> expr = null; if (groups.Any(t => t.Name == Groups.UniqloAdmin.ToString())) { expr = expr.OrContainsIf(o => o.VendorCode, user.VendorCode); expr = expr.OrContainsIf(o => o.BranchFactoryCode, user.BranchFactoryCode); expr = expr.OrContainsIf(o => o.ManagementFactoryCode, user.ManagementFactoryCode); } else { if (groups.Any(t => t.Name == Groups.UniqloVendor.ToString())) { expr = expr.OrContainsIf(o => o.VendorCode, user.VendorCode); } if (groups.Any(t => t.Name == Groups.UniqloBranchFactory.ToString())) { expr = expr.OrContainsIf(o => o.BranchFactoryCode, user.BranchFactoryCode); } if (groups.Any(t => t.Name == Groups.UniqloManagementFactory.ToString())) { expr = expr.OrContainsIf(o => o.ManagementFactoryCode, user.ManagementFactoryCode); } } return list.WhereIf(expr).ToList();
已自己解决。