扩展EF的Fluent API中的 OnModelCreating方法 实现全局数据过滤器

时间:2023-03-08 23:10:13
扩展EF的Fluent API中的 OnModelCreating方法 实现全局数据过滤器

1.生成过滤的表达式目录树

        protected virtual Expression<Func<TEntity, bool>> CreateFilterExpression<TEntity>()
where TEntity : class
{
//构建的表达式目录树 TEntity就是满足条件的每个实体表
Expression<Func<TEntity, bool>> expression = null; //根据租户ID进行过滤数据
//expression = e => ((ILonsidEntity)e).TenantId == LonsidSession.TenantId; // TEntity类型是否继承ISoftDelete
if (typeof(ISoftDelete).IsAssignableFrom(typeof(TEntity)))
{
//过滤出所有没有被软删除的记录
Expression<Func<TEntity, bool>> softDeleteFilter = e => !((ISoftDelete)e).IsDeleted;
//如果当前表达式为Null 就赋值 如果不为null 就把两个表达式组合
expression = expression == null ? softDeleteFilter : CombineExpressions(expression, softDeleteFilter);
} if (typeof(IMayHaveTenant).IsAssignableFrom(typeof(TEntity)))
{
/* This condition should normally be defined as below:
* !IsMayHaveTenantFilterEnabled || ((IMayHaveTenant)e).TenantId == CurrentTenantId
* But this causes a problem with EF Core (see https://github.com/aspnet/EntityFrameworkCore/issues/9502)
* So, we made a workaround to make it working. It works same as above.
*/
Expression<Func<TEntity, bool>> mayHaveTenantFilter = e => ((IMayHaveTenant)e).TenantId == CurrentTenantId || (((IMayHaveTenant)e).TenantId == CurrentTenantId) == IsMayHaveTenantFilterEnabled;
expression = expression == null ? mayHaveTenantFilter : CombineExpressions(expression, mayHaveTenantFilter);
} if (typeof(IMustHaveTenant).IsAssignableFrom(typeof(TEntity)))
{
/* This condition should normally be defined as below:
* !IsMustHaveTenantFilterEnabled || ((IMustHaveTenant)e).TenantId == CurrentTenantId
* But this causes a problem with EF Core (see https://github.com/aspnet/EntityFrameworkCore/issues/9502)
* So, we made a workaround to make it working. It works same as above.
*/
Expression<Func<TEntity, bool>> mustHaveTenantFilter = e => ((IMustHaveTenant)e).TenantId == CurrentTenantId || (((IMustHaveTenant)e).TenantId == CurrentTenantId) == IsMustHaveTenantFilterEnabled;
expression = expression == null ? mustHaveTenantFilter : CombineExpressions(expression, mustHaveTenantFilter);
} return expression;
}

2.配置全局过滤器   将表达式目录树添加进来

        private void ConfigureFilters<TEntity>(ModelBuilder modelBuilder, IMutableEntityType entityType)
where TEntity : class, ILonsidEntity
{
//entityType是否继承了ILonsidEntity
//这里应该不用这个判断 泛型 TEntity 已经有了约束条件 继承了ILonsidEntity
if (typeof(ILonsidEntity).IsAssignableFrom(entityType.ClrType))
{
//创建过滤的表达式目录树
var filterExpression = CreateFilterExpression<TEntity>();
if (filterExpression != null)
{
//将表达式引用到当前实体的任何查询中
modelBuilder.Entity<TEntity>().HasQueryFilter(filterExpression);
}
}
}

3.获取过滤方法

        //通过反射获取当前DbConText中的  配置的全局过滤器方法    这个过滤方法是私有的    要加BindingFlags.NonPublic
private static MethodInfo ConfigureFiltersMethodInfo = typeof(IMSDbContext).GetMethod(nameof(ConfigureFilters), BindingFlags.Instance | BindingFlags.NonPublic);

4.CRUD的时候执行过滤操作

        protected override void OnModelCreating(ModelBuilder modelBuilder)
{
//先调用父类的方法
base.OnModelCreating(modelBuilder);
foreach (var entityType in modelBuilder.Model.GetEntityTypes())
{
//所有继承ILonsidEntity的实体类都需要添加自定义的全局过滤器
if (typeof(ILonsidEntity).IsAssignableFrom(entityType.ClrType))
{
ConfigureFiltersMethodInfo
.MakeGenericMethod(entityType.ClrType)
.Invoke(this, new object[] { modelBuilder, entityType });
}
}
}

*************************************

动态是否使用租户进行过滤的写法

                Expression<Func<TEntity, bool>> mayHaveTenantFilter = e => ((IMayHaveTenant)e).TenantId == CurrentTenantId || (((IMayHaveTenant)e).TenantId == CurrentTenantId) == IsMayHaveTenantFilterEnabled;
((IMayHaveTenant)e).TenantId == CurrentTenantId 前半句已经固定好了  一定会进行过滤租户      

关于后半句IsMayHaveTenantFilterEnabled默认为true  开启租户过滤
(((IMayHaveTenant)e).TenantId == CurrentTenantId) == IsMayHaveTenantFilterEnabled;
1. 如果IsMayHaveTenantFilterEnabled为true 开启过滤
当前数据库中的行满足(((IMayHaveTenant)e).TenantId == CurrentTenantId) 为true 后半句就为true
                                     为false 后半句就为false
  前半句跟后半句的真假性相同  只有租户相等的才会查询出来

2.如果IsMayHaveTenantFilterEnabled为false 禁用过滤
  当前数据库中的行满足(((IMayHaveTenant)e).TenantId == CurrentTenantId) 会给查询出来
  当前数据库中的行不满足(((IMayHaveTenant)e).TenantId == CurrentTenantId) 表达式查询条件变成 false || false == false 后半句永远为true 所以不会进行数据过滤
结论:
IsMayHaveTenantFilterEnabled 为 true  表达式 前半句跟后半句真假性相同  只查询数据行满足租户ID
IsMayHaveTenantFilterEnabled 为false  表达式 前半句跟后半句真假性相反  所有数据库行都满足这个where 条件