mirror of
https://github.com/nsnail/FreeSql.git
synced 2025-04-22 02:32:50 +08:00
91 lines
3.3 KiB
C#
91 lines
3.3 KiB
C#
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<FluentDataFilter> _globalDataFilter;
|
|
|
|
static ConcurrentDictionary<Type, Delegate> _dicSetRepositoryDataFilterApplyDataFilterFunc = new ConcurrentDictionary<Type, Delegate>();
|
|
static ConcurrentDictionary<Type, ConcurrentDictionary<string, bool>> _dicSetRepositoryDataFilterConvertFilterNotExists = new ConcurrentDictionary<Type, ConcurrentDictionary<string, bool>>();
|
|
internal static void SetRepositoryDataFilter(object repos, Action<FluentDataFilter> 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<string, bool>());
|
|
var newFilter = new Dictionary<string, LambdaExpression>();
|
|
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);
|
|
}
|
|
}
|
|
}
|