You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#中FluentValidator在PUT请求中仅验证变更属性的疑问

解决PUT请求中FluentValidator邮箱重复验证误判问题

核心问题分析

当前验证逻辑仅检查邮箱是否存在于数据库,未排除当前要更新的用户自身。当仅修改姓名等非邮箱字段时,当前用户的邮箱本身就存在于库中,因此触发重复错误。

方案一:直接修改查询逻辑(推荐,更高效)

无需额外查询原始用户,直接在邮箱重复检查的SQL中加入ID排除条件:

1. 修正CheckIfEmailIsDuplicate方法

更新SQL语句,传入用户ID以排除当前用户,同时修复原代码中的变量名错误:

private static readonly string QUERY_CHECK_IF_EMAIL_IS_DUPLICATE = 
    "SELECT COUNT(*) FROM User WHERE Email = @email AND Id != @userId";

public async Task<bool> CheckIfEmailIsDuplicate(string email, int userId)
{
    using var connection = dbConnectionFactory.Invoke(DbConnections.DEFAULT_CONNECTION);
    // 修正原代码中SQL变量名拼写错误
    var count = await connection.QueryFirstOrDefaultAsync<int>(
        sql: QUERY_CHECK_IF_EMAIL_IS_DUPLICATE,
        param: new { email, userId });
    return count > 0;
}

2. 更新FluentValidation规则

针对Email字段单独设置规则,传入当前用户ID调用修改后的仓库方法:

RuleFor(r => r.Email)
    .NotEmpty().WithErrorMessage("邮箱不能为空")
    .EmailAddress().WithErrorMessage("邮箱格式不正确")
    .MustAsync(async (user, email, cancellation) =>
    {
        var isDuplicate = await userRepository.CheckIfEmailIsDuplicate(email, user.Id);
        return !isDuplicate;
    })
    .WithErrorMessage("邮箱已存在");

方案二:对比原始用户数据(适用于多字段变更验证场景)

如果需要验证多个字段的变更逻辑,可先查询原始用户数据,对比后再执行验证:

1. 修正GetEmailByIdAsync方法的错误

原方法存在返回类型、参数类型不匹配问题,修正后:

private static readonly string QUERY_GET_USER_BY_ID = @"SELECT * FROM User WHERE Id = @id";

public async Task<User> GetUserByIdAsync(int id)
{
    using var connection = dbConnectionFactory.Invoke(DbConnections.DEFAULT_CONNECTION);
    var user = await connection.QueryFirstOrDefaultAsync<User>(
        sql: QUERY_GET_USER_BY_ID, 
        param: new { id });
    return user;
}

2. 实现变更对比验证逻辑

RuleFor(r => r)
    .NotEmpty().WithErrorMessage("用户对象不能为空")
    .MustAsync(async (updatedUser, cancellation) =>
    {
        var originalUser = await userRepository.GetUserByIdAsync(updatedUser.Id);
        if (originalUser == null)
        {
            return false; // 用户不存在,返回验证失败
        }

        // 仅当邮箱发生变更时,才检查重复
        if (originalUser.Email.Equals(updatedUser.Email, StringComparison.OrdinalIgnoreCase))
        {
            return true; // 邮箱未修改,无需验证重复
        }

        // 邮箱已变更,检查是否与其他用户重复
        var isDuplicate = await userRepository.CheckIfEmailIsDuplicate(updatedUser.Email);
        return !isDuplicate;
    })
    .WithErrorMessage("邮箱已存在或用户不存在");

额外注意事项

  • 原代码中CheckIfEmailIsDuplicate方法存在SQL变量名拼写错误(QUERY_CHECK_IF_EMAIL_IS_DUPLICATES),需修正避免运行时异常。
  • 推荐针对单个字段设置验证规则,而非整个对象,更符合FluentValidation的设计逻辑,也更易维护。

内容的提问来源于stack exchange,提问作者Diogo Miranda

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 19:28:39