feat: 优化多租户配置

This commit is contained in:
chenchun
2025-02-21 18:00:06 +08:00
parent 1fd4f2754a
commit 753b5b0a26
5 changed files with 113 additions and 71 deletions

View File

@@ -22,8 +22,10 @@ namespace Yi.Framework.SqlSugarCore
private IAbpLazyServiceProvider LazyServiceProvider { get; } private IAbpLazyServiceProvider LazyServiceProvider { get; }
private TenantConfigurationWrapper TenantConfigurationWrapper=> LazyServiceProvider.LazyGetRequiredService<TenantConfigurationWrapper>();
private ICurrentTenant CurrentTenant => LazyServiceProvider.LazyGetRequiredService<ICurrentTenant>(); private ICurrentTenant CurrentTenant => LazyServiceProvider.LazyGetRequiredService<ICurrentTenant>();
public DbConnOptions Options => LazyServiceProvider.LazyGetRequiredService<IOptions<DbConnOptions>>().Value;
private DbConnOptions Options => LazyServiceProvider.LazyGetRequiredService<IOptions<DbConnOptions>>().Value;
private ISerializeService SerializeService => LazyServiceProvider.LazyGetRequiredService<ISerializeService>(); private ISerializeService SerializeService => LazyServiceProvider.LazyGetRequiredService<ISerializeService>();
@@ -36,19 +38,13 @@ namespace Yi.Framework.SqlSugarCore
{ {
LazyServiceProvider = lazyServiceProvider; LazyServiceProvider = lazyServiceProvider;
var connectionString = GetCurrentConnectionString(); var tenantConfiguration= AsyncHelper.RunSync(async () =>await TenantConfigurationWrapper.GetAsync());
var connectionConfig =BuildConnectionConfig(action: options => var connectionConfig =BuildConnectionConfig(action: options =>
{ {
options.ConnectionString = connectionString; options.ConnectionString =tenantConfiguration.GetCurrentConnectionString();
options.DbType = GetCurrentDbType(); options.DbType = GetCurrentDbType(tenantConfiguration.GetCurrentConnectionName());
}); });
// var connectionConfig = ConnectionConfigCache.GetOrAdd(connectionString, (_) =>
// BuildConnectionConfig(action: options =>
// {
// options.ConnectionString = connectionString;
// options.DbType = GetCurrentDbType();
// }));
SqlSugarClient = new SqlSugarClient(connectionConfig); SqlSugarClient = new SqlSugarClient(connectionConfig);
//生命周期以下都可以直接使用sqlsugardb了 //生命周期以下都可以直接使用sqlsugardb了
@@ -189,37 +185,14 @@ namespace Yi.Framework.SqlSugarCore
return connectionConfig; return connectionConfig;
} }
/// <summary> protected virtual DbType GetCurrentDbType(string tenantName)
/// db切换多库支持
/// </summary>
/// <returns></returns>
protected virtual string GetCurrentConnectionString()
{ {
var connectionStringResolver = LazyServiceProvider.LazyGetRequiredService<IConnectionStringResolver>(); if (tenantName == ConnectionStrings.DefaultConnectionStringName)
var connectionString =
AsyncHelper.RunSync(() => connectionStringResolver.ResolveAsync());
if (string.IsNullOrWhiteSpace(connectionString))
{ {
Check.NotNull(Options.Url, "dbUrl未配置"); return Options.DbType!.Value;
} }
var dbTypeFromTenantName = GetDbTypeFromTenantName(tenantName);
return connectionString!; return dbTypeFromTenantName!.Value;
}
protected virtual DbType GetCurrentDbType()
{
if (CurrentTenant.Name is not null)
{
var dbTypeFromTenantName = GetDbTypeFromTenantName(CurrentTenant.Name);
if (dbTypeFromTenantName is not null)
{
return dbTypeFromTenantName.Value;
}
}
Check.NotNull(Options.DbType, "默认DbType未配置");
return Options.DbType!.Value;
} }
//根据租户name进行匹配db类型: Test_Sqlite[来自AI] //根据租户name进行匹配db类型: Test_Sqlite[来自AI]

View File

@@ -0,0 +1,79 @@
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.MultiTenancy;
namespace Yi.Framework.SqlSugarCore;
/// <summary>
/// 租户配置
/// </summary>
public class TenantConfigurationWrapper : ITransientDependency
{
private ICurrentTenant _currentTenant;
private ITenantStore _tenantStore;
public TenantConfigurationWrapper(ICurrentTenant currentTenant, ITenantStore tenantStore)
{
_currentTenant = currentTenant;
_tenantStore = tenantStore;
}
/// <summary>
/// 获取租户信息
/// </summary>
/// <returns></returns>
public async Task<TenantConfiguration?> GetAsync()
{
if (_currentTenant.Id is not null)
{
return await _tenantStore.FindAsync(_currentTenant.Id.Value);
}
else if (!string.IsNullOrEmpty(_currentTenant.Name))
{
return await _tenantStore.FindAsync(_currentTenant.Name);
}
else
{
return await _tenantStore.FindAsync(ConnectionStrings.DefaultConnectionStringName);
}
}
/// <summary>
/// 获取当前连接字符串
/// </summary>
/// <returns></returns>
public async Task<string> GetCurrentConnectionStringAsync()
{
return (await GetAsync()).ConnectionStrings.Default!;
}
/// <summary>
/// 获取当前连接名
/// </summary>
/// <returns></returns>
public async Task<string> GetCurrentConnectionNameAsync()
{
return (await GetAsync()).Name;
}
}
public static class TenantConfigurationExtensions
{
/// <summary>
/// 获取当前连接字符串
/// </summary>
/// <returns></returns>
public static string GetCurrentConnectionString(this TenantConfiguration tenantConfiguration)
{
return tenantConfiguration.ConnectionStrings.Default!;
}
/// <summary>
/// 获取当前连接名
/// </summary>
/// <returns></returns>
public static string GetCurrentConnectionName(this TenantConfiguration tenantConfiguration)
{
return tenantConfiguration.Name;
}
}

View File

@@ -15,8 +15,8 @@ namespace Yi.Framework.SqlSugarCore.Uow
{ {
public ILogger<UnitOfWorkSqlsugarDbContextProvider<TDbContext>> Logger { get; set; } public ILogger<UnitOfWorkSqlsugarDbContextProvider<TDbContext>> Logger { get; set; }
public IServiceProvider ServiceProvider { get; set; } public IServiceProvider ServiceProvider { get; set; }
private static AsyncLocalDbContextAccessor ContextInstance => AsyncLocalDbContextAccessor.Instance; private static AsyncLocalDbContextAccessor ContextInstance => AsyncLocalDbContextAccessor.Instance;
protected readonly TenantConfigurationWrapper _tenantConfigurationWrapper;
protected readonly IUnitOfWorkManager UnitOfWorkManager; protected readonly IUnitOfWorkManager UnitOfWorkManager;
protected readonly IConnectionStringResolver ConnectionStringResolver; protected readonly IConnectionStringResolver ConnectionStringResolver;
protected readonly ICancellationTokenProvider CancellationTokenProvider; protected readonly ICancellationTokenProvider CancellationTokenProvider;
@@ -26,26 +26,25 @@ namespace Yi.Framework.SqlSugarCore.Uow
IUnitOfWorkManager unitOfWorkManager, IUnitOfWorkManager unitOfWorkManager,
IConnectionStringResolver connectionStringResolver, IConnectionStringResolver connectionStringResolver,
ICancellationTokenProvider cancellationTokenProvider, ICancellationTokenProvider cancellationTokenProvider,
ICurrentTenant currentTenant ICurrentTenant currentTenant, TenantConfigurationWrapper tenantConfigurationWrapper)
)
{ {
UnitOfWorkManager = unitOfWorkManager; UnitOfWorkManager = unitOfWorkManager;
ConnectionStringResolver = connectionStringResolver; ConnectionStringResolver = connectionStringResolver;
CancellationTokenProvider = cancellationTokenProvider; CancellationTokenProvider = cancellationTokenProvider;
CurrentTenant = currentTenant; CurrentTenant = currentTenant;
_tenantConfigurationWrapper = tenantConfigurationWrapper;
Logger = NullLogger<UnitOfWorkSqlsugarDbContextProvider<TDbContext>>.Instance; Logger = NullLogger<UnitOfWorkSqlsugarDbContextProvider<TDbContext>>.Instance;
} }
public virtual async Task<TDbContext> GetDbContextAsync() public virtual async Task<TDbContext> GetDbContextAsync()
{ {
var connectionStringName = ConnectionStrings.DefaultConnectionStringName;
//获取当前连接字符串,未多租户时,默认为空 //获取当前连接字符串,未多租户时,默认为空
var connectionString = await ResolveConnectionStringAsync(connectionStringName); var tenantConfiguration= await _tenantConfigurationWrapper.GetAsync();
//由于sqlsugar的特殊性没有db区分不再使用连接字符串解析器
var connectionStringName = tenantConfiguration.GetCurrentConnectionName();
var connectionString = tenantConfiguration.GetCurrentConnectionString();
var dbContextKey = $"{this.GetType().Name}_{connectionString}"; var dbContextKey = $"{this.GetType().Name}_{connectionString}";
var unitOfWork = UnitOfWorkManager.Current; var unitOfWork = UnitOfWorkManager.Current;
if (unitOfWork == null ) if (unitOfWork == null )
{ {
@@ -67,8 +66,6 @@ namespace Yi.Framework.SqlSugarCore.Uow
databaseApi = new SqlSugarDatabaseApi( databaseApi = new SqlSugarDatabaseApi(
await CreateDbContextAsync(unitOfWork, connectionStringName, connectionString) await CreateDbContextAsync(unitOfWork, connectionStringName, connectionString)
); );
//await Console.Out.WriteLineAsync(">>>----------------实例化了db"+ ((SqlSugarDatabaseApi)databaseApi).DbContext.SqlSugarClient.ContextID.ToString());
//创建的db加入到当前工作单元中 //创建的db加入到当前工作单元中
unitOfWork.AddDatabaseApi(dbContextKey, databaseApi); unitOfWork.AddDatabaseApi(dbContextKey, databaseApi);
@@ -98,7 +95,7 @@ namespace Yi.Framework.SqlSugarCore.Uow
protected virtual async Task<TDbContext> CreateDbContextWithTransactionAsync(IUnitOfWork unitOfWork) protected virtual async Task<TDbContext> CreateDbContextWithTransactionAsync(IUnitOfWork unitOfWork)
{ {
//事务key //事务key
var transactionApiKey = $"SqlsugarCore_{SqlSugarDbContextCreationContext.Current.ConnectionString}"; var transactionApiKey = $"SqlSugarCore_{SqlSugarDbContextCreationContext.Current.ConnectionString}";
//尝试查找事务 //尝试查找事务
var activeTransaction = unitOfWork.FindTransactionApi(transactionApiKey) as SqlSugarTransactionApi; var activeTransaction = unitOfWork.FindTransactionApi(transactionApiKey) as SqlSugarTransactionApi;
@@ -123,20 +120,5 @@ namespace Yi.Framework.SqlSugarCore.Uow
} }
protected virtual async Task<string> ResolveConnectionStringAsync(string connectionStringName)
{
if (typeof(TDbContext).IsDefined(typeof(IgnoreMultiTenancyAttribute), false))
{
using (CurrentTenant.Change(null))
{
return await ConnectionStringResolver.ResolveAsync(connectionStringName);
}
}
return await ConnectionStringResolver.ResolveAsync(connectionStringName);
}
} }
} }

View File

@@ -10,6 +10,8 @@ using Volo.Abp.Data;
using Volo.Abp.Domain; using Volo.Abp.Domain;
using Volo.Abp.Domain.Repositories; using Volo.Abp.Domain.Repositories;
using Volo.Abp.Guids; using Volo.Abp.Guids;
using Volo.Abp.MultiTenancy;
using Volo.Abp.MultiTenancy.ConfigurationStore;
using Yi.Framework.SqlSugarCore.Abstractions; using Yi.Framework.SqlSugarCore.Abstractions;
using Yi.Framework.SqlSugarCore.Repositories; using Yi.Framework.SqlSugarCore.Repositories;
using Yi.Framework.SqlSugarCore.Uow; using Yi.Framework.SqlSugarCore.Uow;
@@ -69,7 +71,15 @@ namespace Yi.Framework.SqlSugarCore
var dbConfig = section.Get<DbConnOptions>(); var dbConfig = section.Get<DbConnOptions>();
//将默认db传递给abp连接字符串模块 //将默认db传递给abp连接字符串模块
Configure<AbpDbConnectionOptions>(x => { x.ConnectionStrings.Default = dbConfig.Url; }); Configure<AbpDbConnectionOptions>(x => { x.ConnectionStrings.Default = dbConfig.Url; });
//配置abp默认租户
Configure<AbpDefaultTenantStoreOptions>(x => { x.Tenants.AddFirst(new TenantConfiguration
{
Id = Guid.Empty,
Name =$"{ConnectionStrings.DefaultConnectionStringName}",
NormalizedName = ConnectionStrings.DefaultConnectionStringName,
ConnectionStrings = new ConnectionStrings(){{ConnectionStrings.DefaultConnectionStringName,dbConfig.Url}},
IsActive = true
});});
context.Services.AddYiDbContext<DefaultSqlSugarDbContext>(); context.Services.AddYiDbContext<DefaultSqlSugarDbContext>();
return Task.CompletedTask; return Task.CompletedTask;
} }

View File

@@ -53,10 +53,8 @@ public class YiMultiTenantConnectionStringResolver : DefaultConnectionStringReso
: Options.ConnectionStrings.Default!; : Options.ConnectionStrings.Default!;
} }
//Requesting specific connection string... //Requesting specific connection string...
var connString = tenant.ConnectionStrings?.FirstOrDefault().Value; var connString = tenant.ConnectionStrings?.GetOrDefault(connectionStringName);
if (!connString.IsNullOrWhiteSpace()) if (!connString.IsNullOrWhiteSpace())
{ {
//Found for the tenant //Found for the tenant