feat: 增强仓储CRUD与种子配置

This commit is contained in:
2025-12-02 09:46:44 +08:00
parent ffc4f0885f
commit 1a01454266
16 changed files with 587 additions and 56 deletions

View File

@@ -1,9 +1,11 @@
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using TakeoutSaaS.Domain.Dictionary.Entities;
using TakeoutSaaS.Domain.Dictionary.Enums;
using TakeoutSaaS.Domain.Tenants.Entities;
using TakeoutSaaS.Domain.Tenants.Enums;
using TakeoutSaaS.Infrastructure.App.Options;
@@ -142,81 +144,147 @@ public sealed class AppDataSeeder : IHostedService
/// </summary>
private async Task EnsureDictionarySeedsAsync(DictionaryDbContext dbContext, long? defaultTenantId, CancellationToken cancellationToken)
{
if (_options.DictionaryGroups == null || _options.DictionaryGroups.Count == 0)
var dictionaryGroups = _options.DictionaryGroups ?? new List<DictionarySeedGroupOptions>();
var hasDictionaryGroups = dictionaryGroups.Count > 0;
if (!hasDictionaryGroups)
{
_logger.LogInformation("AppSeed 未配置基础字典,跳过字典种子");
}
if (hasDictionaryGroups)
{
foreach (var groupOptions in dictionaryGroups)
{
if (string.IsNullOrWhiteSpace(groupOptions.Code) || string.IsNullOrWhiteSpace(groupOptions.Name))
{
_logger.LogWarning("AppSeed 跳过字典分组Code 或 Name 为空");
continue;
}
var tenantId = groupOptions.TenantId ?? defaultTenantId ?? 0;
var code = groupOptions.Code.Trim();
var group = await dbContext.DictionaryGroups
.IgnoreQueryFilters()
.FirstOrDefaultAsync(x => x.TenantId == tenantId && x.Code == code, cancellationToken);
if (group == null)
{
group = new DictionaryGroup
{
Id = 0,
TenantId = tenantId,
Code = code,
Name = groupOptions.Name.Trim(),
Scope = groupOptions.Scope,
Description = groupOptions.Description?.Trim(),
IsEnabled = groupOptions.IsEnabled
};
await dbContext.DictionaryGroups.AddAsync(group, cancellationToken);
_logger.LogInformation("AppSeed 创建字典分组 {GroupCode} (Tenant: {TenantId})", code, tenantId);
}
else
{
var groupUpdated = false;
if (!string.Equals(group.Name, groupOptions.Name, StringComparison.Ordinal))
{
group.Name = groupOptions.Name.Trim();
groupUpdated = true;
}
if (!string.Equals(group.Description, groupOptions.Description, StringComparison.Ordinal))
{
group.Description = groupOptions.Description?.Trim();
groupUpdated = true;
}
if (group.Scope != groupOptions.Scope)
{
group.Scope = groupOptions.Scope;
groupUpdated = true;
}
if (group.IsEnabled != groupOptions.IsEnabled)
{
group.IsEnabled = groupOptions.IsEnabled;
groupUpdated = true;
}
if (groupUpdated)
{
dbContext.DictionaryGroups.Update(group);
}
}
await UpsertDictionaryItemsAsync(dbContext, group, groupOptions.Items, tenantId, cancellationToken);
}
}
await EnsureSystemParametersAsync(dbContext, defaultTenantId, cancellationToken);
await dbContext.SaveChangesAsync(cancellationToken);
}
/// <summary>
/// 确保系统参数以字典形式幂等种子。
/// </summary>
private async Task EnsureSystemParametersAsync(DictionaryDbContext dbContext, long? defaultTenantId, CancellationToken cancellationToken)
{
var systemParameters = _options.SystemParameters ?? new List<SystemParameterSeedOptions>();
if (systemParameters.Count == 0)
{
_logger.LogInformation("AppSeed 未配置系统参数,跳过系统参数种子");
return;
}
foreach (var groupOptions in _options.DictionaryGroups)
var grouped = systemParameters
.Where(x => !string.IsNullOrWhiteSpace(x.Key) && !string.IsNullOrWhiteSpace(x.Value))
.GroupBy(x => x.TenantId ?? defaultTenantId ?? 0);
if (!grouped.Any())
{
if (string.IsNullOrWhiteSpace(groupOptions.Code) || string.IsNullOrWhiteSpace(groupOptions.Name))
{
_logger.LogWarning("AppSeed 跳过字典分组Code 或 Name 为空");
continue;
}
_logger.LogInformation("AppSeed 系统参数配置为空,跳过系统参数种子");
return;
}
var tenantId = groupOptions.TenantId ?? defaultTenantId ?? 0;
var code = groupOptions.Code.Trim();
var group = await dbContext.DictionaryGroups
foreach (var group in grouped)
{
var tenantId = group.Key;
var dictionaryGroup = await dbContext.DictionaryGroups
.IgnoreQueryFilters()
.FirstOrDefaultAsync(x => x.TenantId == tenantId && x.Code == code, cancellationToken);
.FirstOrDefaultAsync(x => x.TenantId == tenantId && x.Code == "system_parameters", cancellationToken);
if (group == null)
if (dictionaryGroup == null)
{
group = new DictionaryGroup
dictionaryGroup = new DictionaryGroup
{
Id = 0,
TenantId = tenantId,
Code = code,
Name = groupOptions.Name.Trim(),
Scope = groupOptions.Scope,
Description = groupOptions.Description?.Trim(),
IsEnabled = groupOptions.IsEnabled
Code = "system_parameters",
Name = "系统参数",
Scope = tenantId == 0 ? DictionaryScope.System : DictionaryScope.Business,
Description = "系统参数配置",
IsEnabled = true
};
await dbContext.DictionaryGroups.AddAsync(group, cancellationToken);
_logger.LogInformation("AppSeed 创建字典分组 {GroupCode} (Tenant: {TenantId})", code, tenantId);
await dbContext.DictionaryGroups.AddAsync(dictionaryGroup, cancellationToken);
_logger.LogInformation("AppSeed 创建系统参数分组 (Tenant: {TenantId})", tenantId);
}
else
var seedItems = group.Select(x => new DictionarySeedItemOptions
{
var groupUpdated = false;
Key = x.Key.Trim(),
Value = x.Value.Trim(),
Description = x.Description?.Trim(),
SortOrder = x.SortOrder,
IsEnabled = x.IsEnabled
});
if (!string.Equals(group.Name, groupOptions.Name, StringComparison.Ordinal))
{
group.Name = groupOptions.Name.Trim();
groupUpdated = true;
}
if (!string.Equals(group.Description, groupOptions.Description, StringComparison.Ordinal))
{
group.Description = groupOptions.Description?.Trim();
groupUpdated = true;
}
if (group.Scope != groupOptions.Scope)
{
group.Scope = groupOptions.Scope;
groupUpdated = true;
}
if (group.IsEnabled != groupOptions.IsEnabled)
{
group.IsEnabled = groupOptions.IsEnabled;
groupUpdated = true;
}
if (groupUpdated)
{
dbContext.DictionaryGroups.Update(group);
}
}
await UpsertDictionaryItemsAsync(dbContext, group, groupOptions.Items, tenantId, cancellationToken);
await UpsertDictionaryItemsAsync(dbContext, dictionaryGroup, seedItems, tenantId, cancellationToken);
}
await dbContext.SaveChangesAsync(cancellationToken);
}
/// <summary>