自定义 ValidationAttribute:如何检查重复值,忽略正在编辑的对象

Custom ValidationAttribute: How to check for duplicate value, ignoring the object being edited

我正在尝试编写自定义 ValidationAttribute 来验证不存在具有相同值的记录。

问题是,如果用户正在编辑 现有 记录,那么我的代码 找到匹配相同值的记录.如果用户未更改该值,它将找到正在编辑的值。

所以我想我可以将值与 ValidationContext.ObjectInstance 中的值进行比较,以检测它何时未更改,如下所示:

public class UrlTagValidationAttribute : ValidationAttribute
{
    protected override ValidationResult IsValid(object value, ValidationContext context)
    {
        string tag = value as string;
        if (string.IsNullOrWhiteSpace(tag))
            return new ValidationResult("URL Tag is required.");

        // We allow a valid that is equal to the original value
        if (context.ObjectInstance is TrainerModel model && model.Tag == tag)
            return ValidationResult.Success;

        // Cannot be an existing tag
        using (var dbContext = new OnBoard101Entities())
        {
            if (!dbContext.TrainerDetails.Any(td => td.Tag == tag))
                return ValidationResult.Success;
        }

        return new ValidationResult("This URL Tag is not available. Please enter a different one.");
    }
}

但这不起作用。我发现即使在创建新记录时 ValidationContext.ObjectInstance 中的值也经常与输入的值匹配。

我很难找到有关 ValidationContext 当前用法的最新文档。有人可以建议一种方法来检查是否存在与输入值匹配的记录,但在编辑记录且此字段的值未更改时允许它吗?

当前正在编辑的项目很可能有某种 属性 来识别它(在数据库中查找)。因此,您需要获取 属性 以便在搜索数据库中的重复标签时排除它。以下是如何在您的自定义验证中执行此操作 class。我假设标识符被命名为 TrainerId:

public class UrlTagValidationAttribute : ValidationAttribute
{
    protected override ValidationResult IsValid(object value, ValidationContext context)
    {
        string tag = value as string;
        if(string.IsNullOrWhiteSpace(tag))
            return new ValidationResult("URL Tag is required.");

        var currentTrainer = validationContext.ObjectInstance 
                                 as TrainerModel;
        if (currentTrainer == null)
        {
            // What do you want to do? You cannot always return an error
            // because another type could be using this custom validation.
            // Or you can return an error. Depends on your requirements and 
            // and usage.
        }
        using(var dbContext = new OnBoard101Entities())
        {
            if(dbContext.TrainerDetails.Any(td => td.Tag == tag && td.TrainerId != 
                                            currentTrainer.TrainerId))
            {
                return new ValidationResult("This URL Tag is not available. Please enter a different one.");
            }
        }

        return ValidationResult.Success;
    }
}