Abp框架多租户源码解读

1、Abp源码解析

多租户连接字符串处理类(EntityFrameworkCore版本),命名空间为Abp.Zero.EntityFrameworkCore

/// <summary>
/// Implements <see cref="IDbPerTenantConnectionStringResolver"/> to dynamically resolve
/// connection string for a multi tenant application.
/// </summary>
public class DbPerTenantConnectionStringResolver : DefaultConnectionStringResolver, IDbPerTenantConnectionStringResolver

入口方法:

public override string GetNameOrConnectionString(ConnectionStringResolveArgs args)
{
    if (args.MultiTenancySide == MultiTenancySides.Host)
    {
        return GetNameOrConnectionString(new DbPerTenantConnectionStringResolveArgs(null, args));
    }

    return GetNameOrConnectionString(new                                                                     DbPerTenantConnectionStringResolveArgs(GetCurrentTenantId(), args));
}
public class ConnectionStringResolveArgs : Dictionary<string, object>
{
    public MultiTenancySides? MultiTenancySide { get; set; } // 表示当前是租户还是Host

    public ConnectionStringResolveArgs(MultiTenancySides? multiTenancySide = null)
    {
        MultiTenancySide = multiTenancySide;
    }
}

什么时候调用入口方法?初始化DbContext的时候。如iRepository.GetAllList()

这个方法做了什么事情?

public virtual string GetNameOrConnectionString(DbPerTenantConnectionStringResolveArgs args)
{
    if (args.TenantId == null)
    {
        //Host取默认的连接字符串
        return base.GetNameOrConnectionString(args);
    }

    //从缓存中取值
    var tenantCacheItem = _tenantCache.Get(args.TenantId.Value);
    if (tenantCacheItem.ConnectionString.IsNullOrEmpty())
    {
        //租户没配置连接字符串,则返回默认的连接字符串
        return base.GetNameOrConnectionString(args);
    }

    return tenantCacheItem.ConnectionString;
}

看取Host的连接字符串方法:

public virtual string GetNameOrConnectionString(ConnectionStringResolveArgs args)
{
    Check.NotNull(args, nameof(args));

    var defaultConnectionString = _configuration.DefaultNameOrConnectionString;
    if (!string.IsNullOrWhiteSpace(defaultConnectionString))
    {
        return defaultConnectionString;
    }

    if (ConfigurationManager.ConnectionStrings["Default"] != null)
    {
        return "Default";
    }

    if (ConfigurationManager.ConnectionStrings.Count == 1)
    {
        return ConfigurationManager.ConnectionStrings[0].ConnectionString;
    }

    throw new AbpException("Could not find a connection string definition for the application. Set IAbpStartupConfiguration.DefaultNameOrConnectionString or add a 'Default' connection string to application .config file.");
}

问题来了,_tenantCache中哪来的租户配置?看这个Get方法:

public virtual TenantCacheItem Get(int tenantId)
{
    var cacheItem = GetOrNull(tenantId);

    if (cacheItem == null)
    {
        throw new AbpException("There is no tenant with given id: " + tenantId);
    }

    return cacheItem;
}

继续看GetOrNull方法:

public TenantCacheItem GetOrNull(int tenantId)
{
    return _cacheManager
        .GetTenantCache()
        .Get(
            tenantId,
            () =>
            {
                var tenant = GetTenantOrNull(tenantId);
                if (tenant == null)
                {
                    return null;
                }

            return CreateTenantCacheItem(tenant);
            }
        );
}

这个其实就是从缓存中取值,并做了补全功能。继续,看GetTenantOrNull方法:

[UnitOfWork]
protected virtual TTenant GetTenantOrNull(int tenantId)
{
    using (_unitOfWorkManager.Current.SetTenantId(null))
    {
        return _tenantRepository.FirstOrDefault(tenantId);
    }
}

到这里,其实要去租户配置表中查询该租户配置的信息,所以调用了方法_unitOfWorkManager.Current.SetTenantId(null),调用了方法以后,代码执行到_tenantRepository.FirstOrDefault(tenantId)时,会重新调用获取连接字符串的方法,即我们说的入口方法。

最后,拿到Host的数据库连接字符串,_tenantRepository.FirstOrDefault(tenantId)查询当前租户对应的连接字符串。

转载于:https://www.cnblogs.com/yxz1006/p/11321862.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值