feat: migrate snowflake ids and refresh migrations
This commit is contained in:
@@ -10,17 +10,17 @@ public interface IDictionaryAppService
|
||||
{
|
||||
Task<DictionaryGroupDto> CreateGroupAsync(CreateDictionaryGroupRequest request, CancellationToken cancellationToken = default);
|
||||
|
||||
Task<DictionaryGroupDto> UpdateGroupAsync(Guid groupId, UpdateDictionaryGroupRequest request, CancellationToken cancellationToken = default);
|
||||
Task<DictionaryGroupDto> UpdateGroupAsync(long groupId, UpdateDictionaryGroupRequest request, CancellationToken cancellationToken = default);
|
||||
|
||||
Task DeleteGroupAsync(Guid groupId, CancellationToken cancellationToken = default);
|
||||
Task DeleteGroupAsync(long groupId, CancellationToken cancellationToken = default);
|
||||
|
||||
Task<IReadOnlyList<DictionaryGroupDto>> SearchGroupsAsync(DictionaryGroupQuery request, CancellationToken cancellationToken = default);
|
||||
|
||||
Task<DictionaryItemDto> CreateItemAsync(CreateDictionaryItemRequest request, CancellationToken cancellationToken = default);
|
||||
|
||||
Task<DictionaryItemDto> UpdateItemAsync(Guid itemId, UpdateDictionaryItemRequest request, CancellationToken cancellationToken = default);
|
||||
Task<DictionaryItemDto> UpdateItemAsync(long itemId, UpdateDictionaryItemRequest request, CancellationToken cancellationToken = default);
|
||||
|
||||
Task DeleteItemAsync(Guid itemId, CancellationToken cancellationToken = default);
|
||||
Task DeleteItemAsync(long itemId, CancellationToken cancellationToken = default);
|
||||
|
||||
Task<IReadOnlyDictionary<string, IReadOnlyList<DictionaryItemDto>>> GetCachedItemsAsync(DictionaryBatchQueryRequest request, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
@@ -13,15 +13,15 @@ public interface IDictionaryCache
|
||||
/// <summary>
|
||||
/// 获取缓存。
|
||||
/// </summary>
|
||||
Task<IReadOnlyList<DictionaryItemDto>?> GetAsync(Guid tenantId, string code, CancellationToken cancellationToken = default);
|
||||
Task<IReadOnlyList<DictionaryItemDto>?> GetAsync(long tenantId, string code, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// 写入缓存。
|
||||
/// </summary>
|
||||
Task SetAsync(Guid tenantId, string code, IReadOnlyList<DictionaryItemDto> items, CancellationToken cancellationToken = default);
|
||||
Task SetAsync(long tenantId, string code, IReadOnlyList<DictionaryItemDto> items, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// 移除缓存。
|
||||
/// </summary>
|
||||
Task RemoveAsync(Guid tenantId, string code, CancellationToken cancellationToken = default);
|
||||
Task RemoveAsync(long tenantId, string code, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using TakeoutSaaS.Shared.Abstractions.Serialization;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace TakeoutSaaS.Application.Dictionary.Contracts;
|
||||
@@ -11,7 +13,8 @@ public sealed class CreateDictionaryItemRequest
|
||||
/// 所属分组 ID。
|
||||
/// </summary>
|
||||
[Required]
|
||||
public Guid GroupId { get; set; }
|
||||
[JsonConverter(typeof(SnowflakeIdJsonConverter))]
|
||||
public long GroupId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 字典项键。
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
using TakeoutSaaS.Domain.Dictionary.Enums;
|
||||
|
||||
using System.Text.Json.Serialization;
|
||||
using TakeoutSaaS.Shared.Abstractions.Serialization;
|
||||
|
||||
namespace TakeoutSaaS.Application.Dictionary.Models;
|
||||
|
||||
/// <summary>
|
||||
@@ -7,7 +10,8 @@ namespace TakeoutSaaS.Application.Dictionary.Models;
|
||||
/// </summary>
|
||||
public sealed class DictionaryGroupDto
|
||||
{
|
||||
public Guid Id { get; init; }
|
||||
[JsonConverter(typeof(SnowflakeIdJsonConverter))]
|
||||
public long Id { get; init; }
|
||||
|
||||
public string Code { get; init; } = string.Empty;
|
||||
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using TakeoutSaaS.Shared.Abstractions.Serialization;
|
||||
|
||||
namespace TakeoutSaaS.Application.Dictionary.Models;
|
||||
|
||||
/// <summary>
|
||||
@@ -5,9 +8,11 @@ namespace TakeoutSaaS.Application.Dictionary.Models;
|
||||
/// </summary>
|
||||
public sealed class DictionaryItemDto
|
||||
{
|
||||
public Guid Id { get; init; }
|
||||
[JsonConverter(typeof(SnowflakeIdJsonConverter))]
|
||||
public long Id { get; init; }
|
||||
|
||||
public Guid GroupId { get; init; }
|
||||
[JsonConverter(typeof(SnowflakeIdJsonConverter))]
|
||||
public long GroupId { get; init; }
|
||||
|
||||
public string Key { get; init; } = string.Empty;
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ public sealed class DictionaryAppService : IDictionaryAppService
|
||||
|
||||
var group = new DictionaryGroup
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Id = 0,
|
||||
TenantId = targetTenant,
|
||||
Code = normalizedCode,
|
||||
Name = request.Name.Trim(),
|
||||
@@ -62,7 +62,7 @@ public sealed class DictionaryAppService : IDictionaryAppService
|
||||
return MapGroup(group, includeItems: false);
|
||||
}
|
||||
|
||||
public async Task<DictionaryGroupDto> UpdateGroupAsync(Guid groupId, UpdateDictionaryGroupRequest request, CancellationToken cancellationToken = default)
|
||||
public async Task<DictionaryGroupDto> UpdateGroupAsync(long groupId, UpdateDictionaryGroupRequest request, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var group = await RequireGroupAsync(groupId, cancellationToken);
|
||||
EnsureScopePermission(group.Scope);
|
||||
@@ -77,7 +77,7 @@ public sealed class DictionaryAppService : IDictionaryAppService
|
||||
return MapGroup(group, includeItems: false);
|
||||
}
|
||||
|
||||
public async Task DeleteGroupAsync(Guid groupId, CancellationToken cancellationToken = default)
|
||||
public async Task DeleteGroupAsync(long groupId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var group = await RequireGroupAsync(groupId, cancellationToken);
|
||||
EnsureScopePermission(group.Scope);
|
||||
@@ -120,7 +120,7 @@ public sealed class DictionaryAppService : IDictionaryAppService
|
||||
|
||||
var item = new DictionaryItem
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Id = 0,
|
||||
TenantId = group.TenantId,
|
||||
GroupId = group.Id,
|
||||
Key = request.Key.Trim(),
|
||||
@@ -138,7 +138,7 @@ public sealed class DictionaryAppService : IDictionaryAppService
|
||||
return MapItem(item);
|
||||
}
|
||||
|
||||
public async Task<DictionaryItemDto> UpdateItemAsync(Guid itemId, UpdateDictionaryItemRequest request, CancellationToken cancellationToken = default)
|
||||
public async Task<DictionaryItemDto> UpdateItemAsync(long itemId, UpdateDictionaryItemRequest request, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var item = await RequireItemAsync(itemId, cancellationToken);
|
||||
var group = await RequireGroupAsync(item.GroupId, cancellationToken);
|
||||
@@ -156,7 +156,7 @@ public sealed class DictionaryAppService : IDictionaryAppService
|
||||
return MapItem(item);
|
||||
}
|
||||
|
||||
public async Task DeleteItemAsync(Guid itemId, CancellationToken cancellationToken = default)
|
||||
public async Task DeleteItemAsync(long itemId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var item = await RequireItemAsync(itemId, cancellationToken);
|
||||
var group = await RequireGroupAsync(item.GroupId, cancellationToken);
|
||||
@@ -186,8 +186,8 @@ public sealed class DictionaryAppService : IDictionaryAppService
|
||||
|
||||
foreach (var code in normalizedCodes)
|
||||
{
|
||||
var systemItems = await GetOrLoadCacheAsync(Guid.Empty, code, cancellationToken);
|
||||
if (tenantId == Guid.Empty)
|
||||
var systemItems = await GetOrLoadCacheAsync(0, code, cancellationToken);
|
||||
if (tenantId == 0)
|
||||
{
|
||||
result[code] = systemItems;
|
||||
continue;
|
||||
@@ -200,7 +200,7 @@ public sealed class DictionaryAppService : IDictionaryAppService
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task<DictionaryGroup> RequireGroupAsync(Guid groupId, CancellationToken cancellationToken)
|
||||
private async Task<DictionaryGroup> RequireGroupAsync(long groupId, CancellationToken cancellationToken)
|
||||
{
|
||||
var group = await _repository.FindGroupByIdAsync(groupId, cancellationToken);
|
||||
if (group == null)
|
||||
@@ -211,7 +211,7 @@ public sealed class DictionaryAppService : IDictionaryAppService
|
||||
return group;
|
||||
}
|
||||
|
||||
private async Task<DictionaryItem> RequireItemAsync(Guid itemId, CancellationToken cancellationToken)
|
||||
private async Task<DictionaryItem> RequireItemAsync(long itemId, CancellationToken cancellationToken)
|
||||
{
|
||||
var item = await _repository.FindItemByIdAsync(itemId, cancellationToken);
|
||||
if (item == null)
|
||||
@@ -222,16 +222,16 @@ public sealed class DictionaryAppService : IDictionaryAppService
|
||||
return item;
|
||||
}
|
||||
|
||||
private Guid ResolveTargetTenant(DictionaryScope scope)
|
||||
private long ResolveTargetTenant(DictionaryScope scope)
|
||||
{
|
||||
var tenantId = _tenantProvider.GetCurrentTenantId();
|
||||
if (scope == DictionaryScope.System)
|
||||
{
|
||||
EnsurePlatformTenant(tenantId);
|
||||
return Guid.Empty;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (tenantId == Guid.Empty)
|
||||
if (tenantId == 0)
|
||||
{
|
||||
throw new BusinessException(ErrorCodes.BadRequest, "业务参数需指定租户");
|
||||
}
|
||||
@@ -241,28 +241,28 @@ public sealed class DictionaryAppService : IDictionaryAppService
|
||||
|
||||
private static string NormalizeCode(string code) => code.Trim().ToLowerInvariant();
|
||||
|
||||
private static DictionaryScope ResolveScopeForQuery(DictionaryScope? requestedScope, Guid tenantId)
|
||||
private static DictionaryScope ResolveScopeForQuery(DictionaryScope? requestedScope, long tenantId)
|
||||
{
|
||||
if (requestedScope.HasValue)
|
||||
{
|
||||
return requestedScope.Value;
|
||||
}
|
||||
|
||||
return tenantId == Guid.Empty ? DictionaryScope.System : DictionaryScope.Business;
|
||||
return tenantId == 0 ? DictionaryScope.System : DictionaryScope.Business;
|
||||
}
|
||||
|
||||
private void EnsureScopePermission(DictionaryScope scope)
|
||||
{
|
||||
var tenantId = _tenantProvider.GetCurrentTenantId();
|
||||
if (scope == DictionaryScope.System && tenantId != Guid.Empty)
|
||||
if (scope == DictionaryScope.System && tenantId != 0)
|
||||
{
|
||||
throw new BusinessException(ErrorCodes.Forbidden, "仅平台管理员可操作系统字典");
|
||||
}
|
||||
}
|
||||
|
||||
private void EnsurePlatformTenant(Guid tenantId)
|
||||
private void EnsurePlatformTenant(long tenantId)
|
||||
{
|
||||
if (tenantId != Guid.Empty)
|
||||
if (tenantId != 0)
|
||||
{
|
||||
throw new BusinessException(ErrorCodes.Forbidden, "仅平台管理员可操作系统字典");
|
||||
}
|
||||
@@ -279,7 +279,7 @@ public sealed class DictionaryAppService : IDictionaryAppService
|
||||
// 系统参数更新需要逐租户重新合并,由调用方在下一次请求时重新加载
|
||||
}
|
||||
|
||||
private async Task<IReadOnlyList<DictionaryItemDto>> GetOrLoadCacheAsync(Guid tenantId, string code, CancellationToken cancellationToken)
|
||||
private async Task<IReadOnlyList<DictionaryItemDto>> GetOrLoadCacheAsync(long tenantId, string code, CancellationToken cancellationToken)
|
||||
{
|
||||
var cached = await _cache.GetAsync(tenantId, code, cancellationToken);
|
||||
if (cached != null)
|
||||
|
||||
Reference in New Issue
Block a user