需求说明
在开发中,我们常会遇到一个问题,就是归属查询问题,比如只能查看我自己的,往往这个时候还附带了一个规则,比如有人是在这个规则之外的!
1.只能查看创建者自己创建的资料
2.只能查看我店铺的相关内容,不能查看别人店铺的
3.只能查看我部门的相关信息等
可能你会说,直接查询的时候加条件即可!道理就是这么个道理,哪怕是多租户其实也是这样实现的!
** 为啥不直接用多租户呢 **
多租户在我的项目中,用得非常非常少,更多的用的是灵活的协作模式,比如多店铺模式,多商户号模式等!
1.目前的多租户限制比较多,如果引入了,变成店铺+多租户,多了一层关系,别和我说扩展,我感觉扩展还是不如重写来得直接!
2.很多查询,其实并不是严格的多租户模式,比如有些组织,或者个人拥有多个店铺太正常了
3.范围限定,你不能多租户套多租户吧,但是实际需求中往往很多限定的,比如只能查看他自己创建的东西,外面又套了一层店铺
案例分析
在PasteDocument项目中,有这么一个需求,我只能查看我组织的信息,为啥我没用多租户做呢,当时也是考虑使用多租户的,后面放弃了,我宁愿每个表都加一个字段CompanyId
1.Company本身,我有很多自定义的规则
2.多租户用的是Guid,实际中给我的感觉数据库如果没有必要还是不要使用Guid作为主键的好,其实int/long完全够用,当然Guid也有他的优点所在,比如别人猜不到你的日增长,至于说基于id猜数据的,我只能说是你的权限有问题,而不是数据本身!
3.不够灵活,因为我一个用户率属于多个组织太正常了
4.后续扩展考虑
综上,你看需求不就来了么,好了,直接上代码!
解决思路
居然有多租户这个模式,那直接按照他的思路来改即可,对吧!
解读当前方案
下载ABP的源码后,我们在AbpDbContext中看到如下代码,主要是针对多租户的
protected virtual Expression<Func<TEntity, bool>>? CreateFilterExpression<TEntity>()
where TEntity : class
{
Expression<Func<TEntity, bool>>? expression = null;
if (typeof(ISoftDelete).IsAssignableFrom(typeof(TEntity)))
{
expression = e => !IsSoftDeleteFilterEnabled || !EF.Property<bool>(e, "IsDeleted");
}
if (typeof(IMultiTenant).IsAssignableFrom(typeof(TEntity)))
{
Expression<Func<TEntity, bool>> multiTenantFilter = e => !IsMultiTenantFilterEnabled || EF.Property<Guid>(e, "TenantId") == CurrentTenantId;
expression = expression == null ? multiTenantFilter : QueryFilterExpressionHelper.CombineExpressions(expression, multiTenantFilter);
}
return expression;
}
注意看上面的2个被引用的参数
IsMultiTenantFilterEnabled:是否需要过滤多租户
CurrentTenantId:当前的多租户是多少
然后上面的函数意思是基于2个变量生成一个表达式!
看看谁调用他了
protected virtual void ConfigureGlobalFilters<TEntity>(ModelBuilder modelBuilder, IMutableEntityType mutableEntityType)
where TEntity : class
{
if (mutableEntityType.BaseType == null && ShouldFilterEntity<TEntity>(mutableEntityType))
{
var filterExpression = CreateFilterExpression<TEntity>();
if (filterExpression != null)
{
var abc = modelBuilder.Entity<TEntity>();
modelBuilder.Entity<TEntity>().HasAbpQueryFilter(filterExpression);
}
}
}
感觉可以略过,意思就是判断Entity是否继承于设定的IMultiTenant
protected virtual bool ShouldFilterEntity<TEntity>(IMutableEntityType entityType) where TEntity : class
{
if (typeof(IMultiTenant).IsAssignableFrom(typeof(TEntity)))
{
return true;
}
if (typeof(ISoftDelete).IsAssignableFrom(typeof(TEntity)))
{
return true;
}
return false;
}
我们再看看ConfigureGlobalFilters被谁调用了
protected virtual void ConfigureBaseProperties<TEntity>(ModelBuilder modelBuilder, IMutableEntityType mutableEntityType)
where TEntity : class
{
if (mutableEntityType.IsOwned())
{
return;
}
if (!typeof(IEntity).IsAssignableFrom(typeof(TEntity)))
{
return;
}
modelBuilder.Entity<TEntity>().ConfigureByConvention();
ConfigureGlobalFilters<TEntity>(modelBuilder, mutableEntityType);
}
这个判断,啥意思?防止自己调用自己?那估计是有递归查之类的,别管,继续上一级
private static readonly MethodInfo ConfigureBasePropertiesMethodInfo
= typeof(AbpDbContext<TDbContext>)
.GetMethod(