[Abp 源码分析]十二、多租户体系与权限验证 (6)

在 Abp 内部定义了一个借口,叫做 IMustHaveTenant,这玩意儿有一个必须实现的属性 TenantId,所以只要在你的实体继承了该接口,肯定就是会有 TenantId 字段咯,那么 Abp 就可以先判断你当前的实体是否实现了 IMusHaveTenant 接口,如果有的话,就给你创建了一个过滤器拼接到你的查询表达式当中。

protected override void OnModelCreating(ModelBuilder modelBuilder) { // DbContext 模型创建的时候 base.OnModelCreating(modelBuilder); // 遍历所有 DbContext 定义的实体 foreach (var entityType in modelBuilder.Model.GetEntityTypes()) { ConfigureGlobalFiltersMethodInfo .MakeGenericMethod(entityType.ClrType) .Invoke(this, new object[] { modelBuilder, entityType }); } } protected void ConfigureGlobalFilters<TEntity>(ModelBuilder modelBuilder, IMutableEntityType entityType) where TEntity : class { // 判断实体是否实现了租户或者软删除接口,实现了则添加一个过滤器 if (entityType.BaseType == null && ShouldFilterEntity<TEntity>(entityType)) { var filterExpression = CreateFilterExpression<TEntity>(); if (filterExpression != null) { modelBuilder.Entity<TEntity>().HasQueryFilter(filterExpression); } } } // 数据过滤用的查询表达式构建 protected virtual Expression<Func<TEntity, bool>> CreateFilterExpression<TEntity>() where TEntity : class { Expression<Func<TEntity, bool>> expression = null; if (typeof(ISoftDelete).IsAssignableFrom(typeof(TEntity))) { /* This condition should normally be defined as below: * !IsSoftDeleteFilterEnabled || !((ISoftDelete) e).IsDeleted * 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>> softDeleteFilter = e => !((ISoftDelete)e).IsDeleted || ((ISoftDelete)e).IsDeleted != IsSoftDeleteFilterEnabled; 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; }

上面就是实现了,你每次使用 EF Core 查询某个表的实体都会应用这个过滤表达式。

3.1 禁用过滤

但是可以看到在创建表达式的时候这里还有一些诸如 IsSoftDeleteFilterEnabled 的东西,这个就是用于你在某些时候需要禁用掉软删除过滤器的时候所需要用到的。

看看是哪儿来的:

protected virtual bool IsSoftDeleteFilterEnabled => CurrentUnitOfWorkProvider?.Current?.IsFilterEnabled(AbpDataFilters.SoftDelete) == true;

可以看到这个玩意儿是使用当前的工作单元来进行控制的,检测当前工作单元的过滤器是否被启用,如果实体被打了软删除接口,并且被启用的话,那么就执行过滤,反之亦然。

这些过滤器都是放在 AbpDataFilters 当中的,现在有以下几种定义:

public static class AbpDataFilters { public const string SoftDelete = "SoftDelete"; public const string MustHaveTenant = "MustHaveTenant"; public const string MayHaveTenant = "MayHaveTenant"; public static class Parameters { public const string TenantId = "tenantId"; } }

而这些过滤器是在 AbpKernelModule 的预加载方法当中被添加到 UOW 的默认配置当中的。

public override void PreInitialize() { // ... 其他代码 AddUnitOfWorkFilters(); // ... 其他代码 } private void AddUnitOfWorkFilters() { Configuration.UnitOfWork.RegisterFilter(AbpDataFilters.SoftDelete, true); Configuration.UnitOfWork.RegisterFilter(AbpDataFilters.MustHaveTenant, true); Configuration.UnitOfWork.RegisterFilter(AbpDataFilters.MayHaveTenant, true); }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wsxzpd.html