fix: 修复商户中心查询 RowVersion 列不存在问题
All checks were successful
Build and Deploy TenantApi / build-and-deploy (push) Successful in 38s
All checks were successful
Build and Deploy TenantApi / build-and-deploy (push) Successful in 38s
This commit is contained in:
@@ -44,7 +44,7 @@ public sealed record UpdateMerchantCommand : IRequest<UpdateMerchantResultDto?>
|
|||||||
public string? ContactEmail { get; init; }
|
public string? ContactEmail { get; init; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 并发控制版本。
|
/// 并发控制版本(兼容字段,当前由数据库 xmin 托管)。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public byte[] RowVersion { get; init; } = Array.Empty<byte>();
|
public byte[]? RowVersion { get; init; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,16 +29,11 @@ public sealed class UpdateMerchantCommandHandler(
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public async Task<UpdateMerchantResultDto?> Handle(UpdateMerchantCommand request, CancellationToken cancellationToken)
|
public async Task<UpdateMerchantResultDto?> Handle(UpdateMerchantCommand request, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
if (request.RowVersion == null || request.RowVersion.Length == 0)
|
|
||||||
{
|
|
||||||
throw new BusinessException(ErrorCodes.ValidationFailed, "RowVersion 不能为空");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1. 获取操作者权限
|
// 1. 获取操作者权限
|
||||||
var currentTenantId = tenantProvider.GetCurrentTenantId();
|
var currentTenantId = tenantProvider.GetCurrentTenantId();
|
||||||
|
|
||||||
// 2. 读取商户信息
|
// 2. 读取商户信息
|
||||||
var merchant = await merchantRepository.FindByIdAsync(request.MerchantId, currentTenantId, cancellationToken);
|
var merchant = await merchantRepository.GetForUpdateAsync(request.MerchantId, currentTenantId, cancellationToken);
|
||||||
|
|
||||||
if (merchant == null)
|
if (merchant == null)
|
||||||
{
|
{
|
||||||
@@ -73,7 +68,6 @@ public sealed class UpdateMerchantCommandHandler(
|
|||||||
merchant.Address = registeredAddress;
|
merchant.Address = registeredAddress;
|
||||||
merchant.ContactPhone = contactPhone;
|
merchant.ContactPhone = contactPhone;
|
||||||
merchant.ContactEmail = contactEmail;
|
merchant.ContactEmail = contactEmail;
|
||||||
merchant.RowVersion = request.RowVersion;
|
|
||||||
|
|
||||||
var requiresReview = merchant.Status == MerchantStatus.Approved && criticalChanged;
|
var requiresReview = merchant.Status == MerchantStatus.Approved && criticalChanged;
|
||||||
if (requiresReview)
|
if (requiresReview)
|
||||||
|
|||||||
@@ -21,6 +21,5 @@ public sealed class UpdateMerchantCommandValidator : AbstractValidator<UpdateMer
|
|||||||
RuleFor(x => x.ContactPhone).NotEmpty().MaximumLength(32);
|
RuleFor(x => x.ContactPhone).NotEmpty().MaximumLength(32);
|
||||||
RuleFor(x => x.ContactEmail).EmailAddress().MaximumLength(128)
|
RuleFor(x => x.ContactEmail).EmailAddress().MaximumLength(128)
|
||||||
.When(x => !string.IsNullOrWhiteSpace(x.ContactEmail));
|
.When(x => !string.IsNullOrWhiteSpace(x.ContactEmail));
|
||||||
RuleFor(x => x.RowVersion).NotEmpty();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,15 @@ public interface IMerchantRepository
|
|||||||
/// <returns>商户实体或 null。</returns>
|
/// <returns>商户实体或 null。</returns>
|
||||||
Task<Merchant?> FindByIdAsync(long merchantId, long tenantId, CancellationToken cancellationToken = default);
|
Task<Merchant?> FindByIdAsync(long merchantId, long tenantId, CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 依据标识获取商户(用于更新,返回可跟踪实体)。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="merchantId">商户 ID。</param>
|
||||||
|
/// <param name="tenantId">租户 ID。</param>
|
||||||
|
/// <param name="cancellationToken">取消标记。</param>
|
||||||
|
/// <returns>商户实体或 null。</returns>
|
||||||
|
Task<Merchant?> GetForUpdateAsync(long merchantId, long tenantId, CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 按状态筛选商户列表。
|
/// 按状态筛选商户列表。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -536,10 +536,12 @@ public sealed class TakeoutAppDbContext(
|
|||||||
builder.Property(x => x.IsFrozen).HasDefaultValue(false);
|
builder.Property(x => x.IsFrozen).HasDefaultValue(false);
|
||||||
builder.Property(x => x.FrozenReason).HasMaxLength(500);
|
builder.Property(x => x.FrozenReason).HasMaxLength(500);
|
||||||
builder.Property(x => x.ClaimedByName).HasMaxLength(100);
|
builder.Property(x => x.ClaimedByName).HasMaxLength(100);
|
||||||
builder.Property(x => x.RowVersion)
|
builder.Ignore(x => x.RowVersion);
|
||||||
.IsRowVersion()
|
builder.Property<uint>("xmin")
|
||||||
.IsConcurrencyToken()
|
.HasColumnName("xmin")
|
||||||
.HasColumnType("bytea");
|
.HasColumnType("xid")
|
||||||
|
.ValueGeneratedOnAddOrUpdate()
|
||||||
|
.IsConcurrencyToken();
|
||||||
builder.HasIndex(x => x.TenantId);
|
builder.HasIndex(x => x.TenantId);
|
||||||
builder.HasIndex(x => new { x.TenantId, x.Status });
|
builder.HasIndex(x => new { x.TenantId, x.Status });
|
||||||
builder.HasIndex(x => x.ClaimedBy);
|
builder.HasIndex(x => x.ClaimedBy);
|
||||||
|
|||||||
@@ -25,6 +25,14 @@ public sealed class EfMerchantRepository(TakeoutAppDbContext context, TakeoutLog
|
|||||||
.FirstOrDefaultAsync(cancellationToken);
|
.FirstOrDefaultAsync(cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Task<Merchant?> GetForUpdateAsync(long merchantId, long tenantId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return context.Merchants
|
||||||
|
.Where(x => x.TenantId == tenantId && x.Id == merchantId)
|
||||||
|
.FirstOrDefaultAsync(cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public async Task<IReadOnlyList<Merchant>> SearchAsync(long tenantId, MerchantStatus? status, CancellationToken cancellationToken = default)
|
public async Task<IReadOnlyList<Merchant>> SearchAsync(long tenantId, MerchantStatus? status, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user