using SqlSugar; namespace FoodLabeling.Application.Helpers; /// /// 探测 fl_label.AppliedRegionType / fl_label_region 是否已落库,兼容未执行 DDL 的环境。 /// public static class LabelRegionSchemaHelper { private static LabelRegionSchemaStatus? _cached; public sealed class LabelRegionSchemaStatus { public bool HasAppliedRegionTypeColumn { get; init; } public bool HasLabelRegionTable { get; init; } public bool IsFullSchema => HasAppliedRegionTypeColumn && HasLabelRegionTable; } public static async Task GetStatusAsync(ISqlSugarClient db) { if (_cached is not null) { return _cached; } var colCount = await db.Ado.GetIntAsync( """ SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'fl_label' AND COLUMN_NAME = 'AppliedRegionType' """); var tableCount = await db.Ado.GetIntAsync( """ SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'fl_label_region' """); _cached = new LabelRegionSchemaStatus { HasAppliedRegionTypeColumn = colCount > 0, HasLabelRegionTable = tableCount > 0 }; return _cached; } /// 单元测试或切换库后调用。 public static void ResetCacheForTests() => _cached = null; public static async Task GetAppliedRegionTypeForLabelAsync( ISqlSugarClient db, string labelId, string? fallback = null) { var map = await GetAppliedRegionTypesForLabelsAsync(db, new List { labelId }); if (map.TryGetValue(labelId, out var type) && !string.IsNullOrWhiteSpace(type)) { return type.Trim(); } return string.IsNullOrWhiteSpace(fallback) ? LabelRegionScopeHelper.AppliedRegionSpecified : fallback.Trim(); } public static async Task> GetAppliedRegionTypesForLabelsAsync( ISqlSugarClient db, IReadOnlyList labelIds) { var result = new Dictionary(StringComparer.Ordinal); if (labelIds.Count == 0) { return result; } foreach (var id in labelIds) { result[id] = LabelRegionScopeHelper.AppliedRegionSpecified; } var status = await GetStatusAsync(db); if (!status.HasAppliedRegionTypeColumn) { return result; } var ids = labelIds.Where(x => !string.IsNullOrWhiteSpace(x)).Select(x => x.Trim()).Distinct().ToList(); if (ids.Count == 0) { return result; } var rows = await db.Ado.SqlQueryAsync( "SELECT Id, AppliedRegionType FROM fl_label WHERE Id IN (@ids)", new { ids }); foreach (var row in rows) { if (string.IsNullOrWhiteSpace(row.Id)) { continue; } result[row.Id] = string.IsNullOrWhiteSpace(row.AppliedRegionType) ? LabelRegionScopeHelper.AppliedRegionSpecified : row.AppliedRegionType.Trim(); } return result; } public static async Task SetAppliedRegionTypeAsync( ISqlSugarClient db, string labelId, string appliedRegionType) { var status = await GetStatusAsync(db); if (!status.HasAppliedRegionTypeColumn || string.IsNullOrWhiteSpace(labelId)) { return; } await db.Ado.ExecuteCommandAsync( "UPDATE fl_label SET AppliedRegionType = @type WHERE Id = @id", new { type = appliedRegionType.Trim(), id = labelId.Trim() }); } private sealed class LabelAppliedRegionRow { public string Id { get; set; } = string.Empty; public string? AppliedRegionType { get; set; } } }