From 45736dfce9d08eec9727f7c2259e98b09bcad99c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A9=99=E5=AD=90?= <454313500@qq.com> Date: Sat, 22 Feb 2025 15:26:00 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=8C=E6=88=90=E5=A4=9A=E7=A7=9F?= =?UTF-8?q?=E6=88=B7=E4=BC=98=E5=8C=96=E6=94=B9=E9=80=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SqlSugarDbContextFactory.cs | 17 ++++--- .../TenantConfigurationWrapper.cs | 45 ++++++++++++----- .../YiFrameworkSqlSugarCoreModule.cs | 30 +++++++---- .../Services/TestService.cs | 50 +++++++++++++++++++ Yi.Abp.Net8/src/Yi.Abp.Web/appsettings.json | 12 +++++ 5 files changed, 124 insertions(+), 30 deletions(-) diff --git a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/SqlSugarDbContextFactory.cs b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/SqlSugarDbContextFactory.cs index ad3bddd0..67bdb261 100644 --- a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/SqlSugarDbContextFactory.cs +++ b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/SqlSugarDbContextFactory.cs @@ -195,7 +195,7 @@ namespace Yi.Framework.SqlSugarCore return dbTypeFromTenantName!.Value; } - //根据租户name进行匹配db类型: Test_Sqlite,[来自AI] + //根据租户name进行匹配db类型: Test@Sqlite,[form:AI] private DbType? GetDbTypeFromTenantName(string name) { if (string.IsNullOrWhiteSpace(name)) @@ -203,25 +203,26 @@ namespace Yi.Framework.SqlSugarCore 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; } // 提取 枚举 部分 - string enumString = name.Substring(underscoreIndex + 1); + string enumString = name.Substring(atIndex + 1); // 尝试将 尾缀 转换为枚举 if (Enum.TryParse(enumString, out DbType result)) { return result; } - - // 条件不满足时返回 null - return null; + else + { + throw new ArgumentException($"数据库{name}db类型错误或不支持:无法匹配{enumString}数据库类型"); + } } public virtual void BackupDataBase() diff --git a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/TenantConfigurationWrapper.cs b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/TenantConfigurationWrapper.cs index bcfb61cf..420ef296 100644 --- a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/TenantConfigurationWrapper.cs +++ b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/TenantConfigurationWrapper.cs @@ -1,6 +1,8 @@ -using Volo.Abp.Data; +using Microsoft.Extensions.Options; +using Volo.Abp.Data; using Volo.Abp.DependencyInjection; using Volo.Abp.MultiTenancy; +using Yi.Framework.SqlSugarCore.Abstractions; namespace Yi.Framework.SqlSugarCore; @@ -9,33 +11,52 @@ namespace Yi.Framework.SqlSugarCore; /// public class TenantConfigurationWrapper : ITransientDependency { - private ICurrentTenant _currentTenant; - private ITenantStore _tenantStore; + private readonly IAbpLazyServiceProvider _serviceProvider; + private ICurrentTenant CurrentTenant => _serviceProvider.LazyGetRequiredService(); + private ITenantStore TenantStore => _serviceProvider.LazyGetRequiredService(); + private DbConnOptions DbConnOptions => _serviceProvider.LazyGetRequiredService>().Value; - public TenantConfigurationWrapper(ICurrentTenant currentTenant, ITenantStore tenantStore) + public TenantConfigurationWrapper(IAbpLazyServiceProvider serviceProvider) { - _currentTenant = currentTenant; - _tenantStore = tenantStore; + _serviceProvider = serviceProvider; } /// /// 获取租户信息 + /// [from:ai] /// /// public async Task 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); } /// diff --git a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/YiFrameworkSqlSugarCoreModule.cs b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/YiFrameworkSqlSugarCoreModule.cs index c5175be7..d299b91b 100644 --- a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/YiFrameworkSqlSugarCoreModule.cs +++ b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/YiFrameworkSqlSugarCoreModule.cs @@ -53,7 +53,7 @@ namespace Yi.Framework.SqlSugarCore options.DefaultSequentialGuidType = guidType; }); - service.TryAddScoped(); + service.TryAddTransient(); //不开放sqlsugarClient //service.AddTransient(x => x.GetRequiredService().SqlSugarClient); @@ -71,15 +71,25 @@ namespace Yi.Framework.SqlSugarCore var dbConfig = section.Get(); //将默认db传递给abp连接字符串模块 Configure(x => { x.ConnectionStrings.Default = dbConfig.Url; }); - //配置abp默认租户 - Configure(x => { x.Tenants.AddFirst(new TenantConfiguration - { - Id = Guid.Empty, - Name =$"{ConnectionStrings.DefaultConnectionStringName}", - NormalizedName = ConnectionStrings.DefaultConnectionStringName, - ConnectionStrings = new ConnectionStrings(){{ConnectionStrings.DefaultConnectionStringName,dbConfig.Url}}, - IsActive = true - });}); + //配置abp默认租户,对接abp模块 + Configure(x => { + var tenantList = x.Tenants.ToList(); + foreach(var tenant in tenantList) + { + tenant.NormalizedName = tenant.Name.Contains("@") ? + tenant.Name.Substring(0, tenant.Name.LastIndexOf("@")) : + 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(); return Task.CompletedTask; } diff --git a/Yi.Abp.Net8/src/Yi.Abp.Application/Services/TestService.cs b/Yi.Abp.Net8/src/Yi.Abp.Application/Services/TestService.cs index da686753..7b0a0833 100644 --- a/Yi.Abp.Net8/src/Yi.Abp.Application/Services/TestService.cs +++ b/Yi.Abp.Net8/src/Yi.Abp.Application/Services/TestService.cs @@ -5,6 +5,8 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.RateLimiting; using Volo.Abp.Application.Services; using Volo.Abp.DistributedLocking; +using Volo.Abp.Domain.Repositories; +using Volo.Abp.MultiTenancy; using Volo.Abp.Settings; using Volo.Abp.Uow; using Yi.Framework.Bbs.Application.Contracts.Dtos.Banner; @@ -215,5 +217,53 @@ namespace Yi.Abp.Application.Services }); return $"加锁结果:{number},不加锁结果:{number2}"; } + + public ICurrentTenant CurrentTenant { get; set; } + public IRepository repository { get; set; } + /// + /// 多租户 + /// + /// + public async Task 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实例连接,涉及多库事务统一到最后提交"; + } + + } } } \ No newline at end of file diff --git a/Yi.Abp.Net8/src/Yi.Abp.Web/appsettings.json b/Yi.Abp.Net8/src/Yi.Abp.Web/appsettings.json index 9e9bec22..d8ad0039 100644 --- a/Yi.Abp.Net8/src/Yi.Abp.Web/appsettings.json +++ b/Yi.Abp.Net8/src/Yi.Abp.Web/appsettings.json @@ -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": { "LogLevel": { //"Default": "Information",