e41dfa09
李曜臣
泰鄂版菜单;租户列表
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
|
using FoodLabeling.Th.Application.Contracts.Options;
using SqlSugar;
using Volo.Abp;
using Yi.Framework.TenantManagement.Domain;
namespace FoodLabeling.Th.Application.MultiTenancy;
/// <summary>
/// 跨租户操作业务库:解析/回填连接串并用独立 SqlSugarClient 直连,避免 CurrentTenant.Change 解析空连接串。
/// </summary>
public static class TenantBusinessDatabaseAccessor
{
private const string InitializeTenantDatabaseHintTemplate =
"请先调用 POST /api/app/th-tenant-provisioning/initialize-tenant-database/{0} 初始化业务库";
/// <summary>
/// 解析租户业务库连接串;为空时按配置回填并写回主库 YiTenant。
/// </summary>
public static async Task<(string ConnectionString, DbType DbType)> ResolveConnectionAsync(
TenantAggregateRoot tenant,
FoodLabelingThTenantDatabaseOptions dbOptions,
Func<TenantAggregateRoot, Task> 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);
}
/// <summary>
/// 创建直连租户业务库的 SqlSugar 客户端(调用方 using 释放)。
/// </summary>
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
});
}
/// <summary>
/// 探测业务库是否可连;库不存在时给出初始化引导。
/// </summary>
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);
}
}
|