ABP vNext 实现租户Id自动赋值插入-LMLPHP

背景

在使用ABP vNext过程中,因为我们的用户体系庞大,所以一直与其他业务同时开发,在开发其他业务模块时,我们一直存在着误区:认为ABP vNext 自动处理了数据新增时的租户Id(TenantId)的自动赋值插入。直到我们开始接入用户权限模块后,发现并不如此。

思路

为了实现字段的自动赋值,且无感知的,我们的思路是做类似拦截器,在上层应用新增数据相关代码流程进入DbContext的时候,在DbContext中进行处理。

其他

问题

为了实现上层业务开发人员的【无感知】,哪怕在代码编写过程中,我们也不希望开发人员有所明显感知自己在使用经过处理的DbContext,于是想到了与Volo.Abp.EntityFrameworkCore.AbpDbContext使用同一个名字AbpDbContext。

解决方案

我们首先知道,在C#中,如果有两个命名空间下,具有同名类,那么两个类的优先级为何。

假设,我们写的类在:TripleH.AbpDbContext。我们在使用这个类的地方的命名空间为:TripleH.*.AClass。

那么在AClass中使用AbpDbContext时,我们就算引用了Volo.Abp.EntityFrameworkCore命名空间,编译时也会使用TripleH.AbpDbContext。

这是因为,C#在此处的优先级决定的,它优先找Triple.*命名空间下的AbpDbContext这个类,如果没有,就会逐级往上,找Triple命名空间下的AbpDbContext,如果找到了,就会直接使用它,使用时连命名空间都不需要手动引用。当然,如果没找过,才会去其他命名空间如Volo.Abp.EntityFrameworkCore中寻找。

实现

namespace TripleH
{
    public abstract class AbpDbContext<TDbContext> : Volo.Abp.EntityFrameworkCore.AbpDbContext<TDbContext>
        where TDbContext : AbpDbContext<TDbContext>
    {
        public AbpDbContext(DbContextOptions<TDbContext> options)
            : base(options)
        {

        }

        protected override void ApplyAbpConceptsForAddedEntity(EntityEntry entry, EntityChangeReport changeReport)
        {
            SetTenantIdIfNull(entry);
            base.ApplyAbpConceptsForAddedEntity(entry, changeReport);
        }

        protected virtual void SetTenantIdIfNull(EntityEntry entry)
        {
            if (entry.Entity is IMultiTenant entityWithTenantId
                && entityWithTenantId.TenantId == null
                && IsMultiTenantFilterEnabled)
            {
                ObjectHelper.TrySetProperty(entityWithTenantId, e => e.TenantId, () => CurrentTenant.Id);
            }
        }
    }
}

使用

//无需额外引用TripleH命名空间,做到真正的无感知,当然鼠标放到AbpDbContext上,VS 会告诉你是哪个命名空间
namespace TripleH.Test.EntityFrameworkCore
{
    //此处继承的AbpDbContext,便是来自TripleH命名空间下,而非Abp
    [ConnectionStringName(BasicDbProperties.ConnectionStringName)]
    public class BasicDbContext : AbpDbContext<BasicDbContext>, IBasicDbContext
    {
        public BasicDbContext(DbContextOptions<BasicDbContext> options)
            : base(options)
        {

        }

        protected override void OnModelCreating(ModelBuilder builder)
        {
            base.OnModelCreating(builder);

            builder.ConfigureBasic();
        }
    }
}

ABP vNext 实现租户Id自动赋值插入-LMLPHP

01-23 18:41