using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Text; namespace FreeSql { internal class Utils { internal static Action _globalDataFilter; static ConcurrentDictionary _dicSetRepositoryDataFilterApplyDataFilterFunc = new ConcurrentDictionary(); static ConcurrentDictionary> _dicSetRepositoryDataFilterConvertFilterNotExists = new ConcurrentDictionary>(); internal static void SetRepositoryDataFilter(object repos, Action scopedDataFilter) { if (scopedDataFilter != null) { SetRepositoryDataFilter(repos, null); } if (scopedDataFilter == null) { scopedDataFilter = _globalDataFilter; } if (scopedDataFilter == null) return; using (var globalFilter = new FluentDataFilter()) { scopedDataFilter(globalFilter); var type = repos.GetType(); Type entityType = (repos as IRepository).EntityType; if (entityType == null) throw new Exception("FreeSql.Repository 设置过滤器失败,原因是对象不属于 IRepository"); var notExists = _dicSetRepositoryDataFilterConvertFilterNotExists.GetOrAdd(type, t => new ConcurrentDictionary()); var newFilter = new Dictionary(); foreach (var gf in globalFilter._filters) { if (notExists.ContainsKey(gf.name)) continue; LambdaExpression newExp = null; var filterParameter1 = Expression.Parameter(entityType, gf.exp.Parameters[0].Name); try { newExp = Expression.Lambda( typeof(Func<,>).MakeGenericType(entityType, typeof(bool)), new ReplaceVisitor().Modify(gf.exp.Body, filterParameter1), filterParameter1 ); } catch { notExists.TryAdd(gf.name, true); //防止第二次错误 continue; } newFilter.Add(gf.name, gf.exp); } if (newFilter.Any() == false) return; var del = _dicSetRepositoryDataFilterApplyDataFilterFunc.GetOrAdd(type, t => { var reposParameter = Expression.Parameter(type); var nameParameter = Expression.Parameter(typeof(string)); var expressionParameter = Expression.Parameter( typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(entityType, typeof(bool))) ); return Expression.Lambda( Expression.Block( Expression.Call(reposParameter, type.GetMethod("ApplyDataFilter", BindingFlags.Instance | BindingFlags.NonPublic), nameParameter, expressionParameter) ), new[] { reposParameter, nameParameter, expressionParameter } ).Compile(); }); foreach (var nf in newFilter) { del.DynamicInvoke(repos, nf.Key, nf.Value); } newFilter.Clear(); } } } class ReplaceVisitor : ExpressionVisitor { private ParameterExpression parameter; public Expression Modify(Expression expression, ParameterExpression parameter) { this.parameter = parameter; return Visit(expression); } protected override Expression VisitMember(MemberExpression node) { if (node.Expression?.NodeType == ExpressionType.Parameter) return Expression.Property(parameter, node.Member.Name); return base.VisitMember(node); } } }