using FoodLabeling.Th.Application.Contracts.Options; using SqlSugar; using Volo.Abp; using Yi.Framework.TenantManagement.Domain; namespace FoodLabeling.Th.Application.MultiTenancy; /// /// 跨租户操作业务库:解析/回填连接串并用独立 SqlSugarClient 直连,避免 CurrentTenant.Change 解析空连接串。 /// public static class TenantBusinessDatabaseAccessor { private const string InitializeTenantDatabaseHintTemplate = "请先调用 POST /api/app/th-tenant-provisioning/initialize-tenant-database/{0} 初始化业务库"; /// /// 解析租户业务库连接串;为空时按配置回填并写回主库 YiTenant。 /// public static async Task<(string ConnectionString, DbType DbType)> ResolveConnectionAsync( TenantAggregateRoot tenant, FoodLabelingThTenantDatabaseOptions dbOptions, Func persistTenantAsync) { var connectionString = tenant.TenantConnectionString?.Trim(); if (!string.IsNullOrWhiteSpace(connectionString)) { return (connectionString, ResolveDbType(tenant.DbType)); } connectionString = TenantDatabaseConnectionStringBuilder.BuildMySqlConnectionString( dbOptions, tenant.Name); if (string.IsNullOrWhiteSpace(connectionString)) { throw BuildMissingConnectionStringException(tenant.Name); } var dbType = DbType.MySql; tenant.SetConnectionString(dbType, connectionString); await persistTenantAsync(tenant); return (connectionString, dbType); } /// /// 创建直连租户业务库的 SqlSugar 客户端(调用方 using 释放)。 /// public static SqlSugarClient CreateClient(string connectionString, DbType dbType) { if (string.IsNullOrWhiteSpace(connectionString)) { throw new UserFriendlyException("租户业务库连接串不能为空"); } return new SqlSugarClient(new ConnectionConfig { ConfigId = $"th-tenant-direct-{Guid.NewGuid():N}", DbType = dbType, ConnectionString = connectionString, IsAutoCloseConnection = true }); } /// /// 探测业务库是否可连;库不存在时给出初始化引导。 /// public static void EnsureDatabaseReachable(ISqlSugarClient db, Guid tenantId) { try { db.Ado.ExecuteCommand("SELECT 1"); } catch (Exception ex) when (IsDatabaseNotExistError(ex)) { throw new UserFriendlyException( string.Format(InitializeTenantDatabaseHintTemplate, tenantId)); } } public static UserFriendlyException BuildMissingConnectionStringException(string tenantName) { return new UserFriendlyException( $"租户「{tenantName}」未配置业务库连接串,请先在租户管理完善连接串或调用开通/初始化接口"); } private static DbType ResolveDbType(DbType tenantDbType) { return tenantDbType == default ? DbType.MySql : tenantDbType; } private static bool IsDatabaseNotExistError(Exception ex) { var message = ex.Message; var current = ex; while (current.InnerException != null) { current = current.InnerException; message += " " + current.Message; } return message.Contains("Unknown database", StringComparison.OrdinalIgnoreCase) || message.Contains("doesn't exist", StringComparison.OrdinalIgnoreCase) || message.Contains("1049", StringComparison.Ordinal); } }