feat: 完成多租户优化改造
This commit is contained in:
@@ -195,7 +195,7 @@ namespace Yi.Framework.SqlSugarCore
|
|||||||
return dbTypeFromTenantName!.Value;
|
return dbTypeFromTenantName!.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
//根据租户name进行匹配db类型: Test_Sqlite,[来自AI]
|
//根据租户name进行匹配db类型: Test@Sqlite,[form:AI]
|
||||||
private DbType? GetDbTypeFromTenantName(string name)
|
private DbType? GetDbTypeFromTenantName(string name)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(name))
|
if (string.IsNullOrWhiteSpace(name))
|
||||||
@@ -203,25 +203,26 @@ namespace Yi.Framework.SqlSugarCore
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查找下划线的位置
|
// 查找@符号的位置
|
||||||
int underscoreIndex = name.LastIndexOf('_');
|
int atIndex = name.LastIndexOf('@');
|
||||||
|
|
||||||
if (underscoreIndex == -1 || underscoreIndex == name.Length - 1)
|
if (atIndex == -1 || atIndex == name.Length - 1)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 提取 枚举 部分
|
// 提取 枚举 部分
|
||||||
string enumString = name.Substring(underscoreIndex + 1);
|
string enumString = name.Substring(atIndex + 1);
|
||||||
|
|
||||||
// 尝试将 尾缀 转换为枚举
|
// 尝试将 尾缀 转换为枚举
|
||||||
if (Enum.TryParse<DbType>(enumString, out DbType result))
|
if (Enum.TryParse<DbType>(enumString, out DbType result))
|
||||||
{
|
{
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
// 条件不满足时返回 null
|
{
|
||||||
return null;
|
throw new ArgumentException($"数据库{name}db类型错误或不支持:无法匹配{enumString}数据库类型");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void BackupDataBase()
|
public virtual void BackupDataBase()
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
using Volo.Abp.Data;
|
using Microsoft.Extensions.Options;
|
||||||
|
using Volo.Abp.Data;
|
||||||
using Volo.Abp.DependencyInjection;
|
using Volo.Abp.DependencyInjection;
|
||||||
using Volo.Abp.MultiTenancy;
|
using Volo.Abp.MultiTenancy;
|
||||||
|
using Yi.Framework.SqlSugarCore.Abstractions;
|
||||||
|
|
||||||
namespace Yi.Framework.SqlSugarCore;
|
namespace Yi.Framework.SqlSugarCore;
|
||||||
|
|
||||||
@@ -9,33 +11,52 @@ namespace Yi.Framework.SqlSugarCore;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class TenantConfigurationWrapper : ITransientDependency
|
public class TenantConfigurationWrapper : ITransientDependency
|
||||||
{
|
{
|
||||||
private ICurrentTenant _currentTenant;
|
private readonly IAbpLazyServiceProvider _serviceProvider;
|
||||||
private ITenantStore _tenantStore;
|
private ICurrentTenant CurrentTenant => _serviceProvider.LazyGetRequiredService<ICurrentTenant>();
|
||||||
|
private ITenantStore TenantStore => _serviceProvider.LazyGetRequiredService<ITenantStore>();
|
||||||
|
private DbConnOptions DbConnOptions => _serviceProvider.LazyGetRequiredService<IOptions<DbConnOptions>>().Value;
|
||||||
|
|
||||||
public TenantConfigurationWrapper(ICurrentTenant currentTenant, ITenantStore tenantStore)
|
public TenantConfigurationWrapper(IAbpLazyServiceProvider serviceProvider)
|
||||||
{
|
{
|
||||||
_currentTenant = currentTenant;
|
_serviceProvider = serviceProvider;
|
||||||
_tenantStore = tenantStore;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取租户信息
|
/// 获取租户信息
|
||||||
|
/// [from:ai]
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task<TenantConfiguration?> GetAsync()
|
public async Task<TenantConfiguration?> GetAsync()
|
||||||
{
|
{
|
||||||
if (_currentTenant.Id is not null)
|
//未开启多租户
|
||||||
|
if (!DbConnOptions.EnabledSaasMultiTenancy)
|
||||||
{
|
{
|
||||||
return await _tenantStore.FindAsync(_currentTenant.Id.Value);
|
return await TenantStore.FindAsync(ConnectionStrings.DefaultConnectionStringName);
|
||||||
}
|
}
|
||||||
else if (!string.IsNullOrEmpty(_currentTenant.Name))
|
|
||||||
|
TenantConfiguration? tenantConfiguration = null;
|
||||||
|
|
||||||
|
if (CurrentTenant.Id is not null)
|
||||||
{
|
{
|
||||||
return await _tenantStore.FindAsync(_currentTenant.Name);
|
tenantConfiguration = await TenantStore.FindAsync(CurrentTenant.Id.Value);
|
||||||
|
if (tenantConfiguration == null)
|
||||||
|
{
|
||||||
|
throw new ApplicationException($"未找到租户信息,租户Id:{CurrentTenant.Id}");
|
||||||
|
}
|
||||||
|
return tenantConfiguration;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if (!string.IsNullOrEmpty(CurrentTenant.Name))
|
||||||
{
|
{
|
||||||
return await _tenantStore.FindAsync(ConnectionStrings.DefaultConnectionStringName);
|
tenantConfiguration = await TenantStore.FindAsync(CurrentTenant.Name);
|
||||||
|
if (tenantConfiguration == null)
|
||||||
|
{
|
||||||
|
throw new ApplicationException($"未找到租户信息,租户名称:{CurrentTenant.Name}");
|
||||||
|
}
|
||||||
|
return tenantConfiguration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return await TenantStore.FindAsync(ConnectionStrings.DefaultConnectionStringName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ namespace Yi.Framework.SqlSugarCore
|
|||||||
options.DefaultSequentialGuidType = guidType;
|
options.DefaultSequentialGuidType = guidType;
|
||||||
});
|
});
|
||||||
|
|
||||||
service.TryAddScoped<ISqlSugarDbContext, SqlSugarDbContextFactory>();
|
service.TryAddTransient<ISqlSugarDbContext, SqlSugarDbContextFactory>();
|
||||||
|
|
||||||
//不开放sqlsugarClient
|
//不开放sqlsugarClient
|
||||||
//service.AddTransient<ISqlSugarClient>(x => x.GetRequiredService<ISqlsugarDbContext>().SqlSugarClient);
|
//service.AddTransient<ISqlSugarClient>(x => x.GetRequiredService<ISqlsugarDbContext>().SqlSugarClient);
|
||||||
@@ -71,15 +71,25 @@ 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默认租户
|
//配置abp默认租户,对接abp模块
|
||||||
Configure<AbpDefaultTenantStoreOptions>(x => { x.Tenants.AddFirst(new TenantConfiguration
|
Configure<AbpDefaultTenantStoreOptions>(x => {
|
||||||
{
|
var tenantList = x.Tenants.ToList();
|
||||||
Id = Guid.Empty,
|
foreach(var tenant in tenantList)
|
||||||
Name =$"{ConnectionStrings.DefaultConnectionStringName}",
|
{
|
||||||
NormalizedName = ConnectionStrings.DefaultConnectionStringName,
|
tenant.NormalizedName = tenant.Name.Contains("@") ?
|
||||||
ConnectionStrings = new ConnectionStrings(){{ConnectionStrings.DefaultConnectionStringName,dbConfig.Url}},
|
tenant.Name.Substring(0, tenant.Name.LastIndexOf("@")) :
|
||||||
IsActive = true
|
tenant.Name;
|
||||||
});});
|
}
|
||||||
|
tenantList.Insert(0, new TenantConfiguration
|
||||||
|
{
|
||||||
|
Id = Guid.Empty,
|
||||||
|
Name = $"{ConnectionStrings.DefaultConnectionStringName}",
|
||||||
|
NormalizedName = ConnectionStrings.DefaultConnectionStringName,
|
||||||
|
ConnectionStrings = new ConnectionStrings() { { ConnectionStrings.DefaultConnectionStringName, dbConfig.Url } },
|
||||||
|
IsActive = true
|
||||||
|
});
|
||||||
|
x.Tenants = tenantList.ToArray();
|
||||||
|
});
|
||||||
context.Services.AddYiDbContext<DefaultSqlSugarDbContext>();
|
context.Services.AddYiDbContext<DefaultSqlSugarDbContext>();
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ using Microsoft.AspNetCore.Mvc;
|
|||||||
using Microsoft.AspNetCore.RateLimiting;
|
using Microsoft.AspNetCore.RateLimiting;
|
||||||
using Volo.Abp.Application.Services;
|
using Volo.Abp.Application.Services;
|
||||||
using Volo.Abp.DistributedLocking;
|
using Volo.Abp.DistributedLocking;
|
||||||
|
using Volo.Abp.Domain.Repositories;
|
||||||
|
using Volo.Abp.MultiTenancy;
|
||||||
using Volo.Abp.Settings;
|
using Volo.Abp.Settings;
|
||||||
using Volo.Abp.Uow;
|
using Volo.Abp.Uow;
|
||||||
using Yi.Framework.Bbs.Application.Contracts.Dtos.Banner;
|
using Yi.Framework.Bbs.Application.Contracts.Dtos.Banner;
|
||||||
@@ -215,5 +217,53 @@ namespace Yi.Abp.Application.Services
|
|||||||
});
|
});
|
||||||
return $"加锁结果:{number},不加锁结果:{number2}";
|
return $"加锁结果:{number},不加锁结果:{number2}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ICurrentTenant CurrentTenant { get; set; }
|
||||||
|
public IRepository<BannerAggregateRoot> repository { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 多租户
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<string> GetMultiTenantAsync()
|
||||||
|
{
|
||||||
|
using (var uow=UnitOfWorkManager.Begin())
|
||||||
|
{
|
||||||
|
//此处会实例化一个db,连接默认库
|
||||||
|
var defautTenantData1= await repository.GetListAsync();
|
||||||
|
using (CurrentTenant.Change(null,"Default"))
|
||||||
|
{
|
||||||
|
var defautTenantData2= await repository.GetListAsync();
|
||||||
|
await repository.InsertAsync(new BannerAggregateRoot
|
||||||
|
{
|
||||||
|
Name = "default",
|
||||||
|
});
|
||||||
|
var defautTenantData3= await repository.GetListAsync(x=>x.Name=="default");
|
||||||
|
}
|
||||||
|
//此处会实例化一个新的db连接MES
|
||||||
|
using (CurrentTenant.Change(null,"Mes"))
|
||||||
|
{
|
||||||
|
var otherTenantData1= await repository.GetListAsync();
|
||||||
|
await repository.InsertAsync(new BannerAggregateRoot
|
||||||
|
{
|
||||||
|
Name = "Mes1",
|
||||||
|
});
|
||||||
|
var otherTenantData2= await repository.GetListAsync(x=>x.Name=="Mes1");
|
||||||
|
}
|
||||||
|
//此处会复用Mesdb,不会实例化新的db
|
||||||
|
using (CurrentTenant.Change(Guid.Parse("33333333-3d72-4339-9adc-845151f8ada0")))
|
||||||
|
{
|
||||||
|
var otherTenantData1= await repository.GetListAsync();
|
||||||
|
await repository.InsertAsync(new BannerAggregateRoot
|
||||||
|
{
|
||||||
|
Name = "Mes2",
|
||||||
|
});
|
||||||
|
var otherTenantData2= await repository.GetListAsync(x=>x.Name=="Mes2");
|
||||||
|
}
|
||||||
|
//此处会将多库进行一起提交,前面的操作有报错,全部回滚
|
||||||
|
await uow.CompleteAsync();
|
||||||
|
return "根据租户切换不同的数据库,并管理db实例连接,涉及多库事务统一到最后提交";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,16 @@
|
|||||||
{
|
{
|
||||||
|
//多租户,支持多库,DbConnOptions会自动创建到默认租户,支持配置文件方式+数据库方式,AbpDefaultTenantStoreOptions
|
||||||
|
// "Tenants": [
|
||||||
|
// {
|
||||||
|
// "Id": "33333333-3d72-4339-9adc-845151f8ada0",
|
||||||
|
// "Name": "Mes@MySql",
|
||||||
|
// "ConnectionStrings": {
|
||||||
|
// "Default": "DataSource=mes-dev.db"
|
||||||
|
// },
|
||||||
|
// "IsActive": false
|
||||||
|
// }
|
||||||
|
// ],
|
||||||
|
|
||||||
"Logging": {
|
"Logging": {
|
||||||
"LogLevel": {
|
"LogLevel": {
|
||||||
//"Default": "Information",
|
//"Default": "Information",
|
||||||
|
|||||||
Reference in New Issue
Block a user