实体框架如何使验证仅发生在实体上,而不发生在基础实体上

本文关键字:实体 框架 验证 何使 | 更新日期: 2023-09-27 17:57:45

我的所有实体都继承自IValidatableObject。我遇到的问题是,当我保存一个实体,而这个实体包含一个引用另一个未完全加载的实体的属性(它不是null,但只包含里面有引用键的对象)时,代码会引发错误。错误在于属性(引用另一个实体)未正确验证。这是真的,因为对象只包含ID。让我用一个小例子告诉你我在说什么:

public class Exercise : BaseModel
{
    public LocalizedString Name { get; set; }
    public virtual Muscle Muscle { get; set; }
    public override IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (Name == null)
        {
            yield return new ValidationResult("Name is mandatory", new[] { "Name" });
            yield break;
        }
        if (Name.French == null || Name.French.Length < 3)
        {
            yield return new ValidationResult("Exercise's French name must be over 3 characters");
        }
        if (Name.English == null || Name.English.Length < 3)
        {
            yield return new ValidationResult("Exercise's English name must be over 3 characters");
        }
        if (Muscle == null)
        {
            yield return new ValidationResult("Exercice must be assigned to a muscle");
        }
    }
}
public class Muscle : BaseModel
{
    public LocalizedString Name { get; set; }
    public ICollection<Exercise> Exercises { get; set; }
    public override IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (Name == null)
        {
            yield return new ValidationResult("Name is mandatory", new[] { "Name" });
            yield break;
        }
        if (Name.French == null || Name.French.Length < 3)
        {
            yield return new ValidationResult("Muscle's French name must be over 3 characters");
        }
        if (Name.English == null || Name.English.Length < 3)
        {
            yield return new ValidationResult("Muscle's English name must be over 3 characters");
        }
    }
}
//--- This is the code into the repository:
public int Insert(Exercise entity)
{
    if (entity.Muscle != null)
    {
        var localExercise = DatabaseContext.Set<Muscle>().Local.SingleOrDefault(e => e.Id == entity.Muscle.Id);
        if (localExercise != null)
        {
            DatabaseContext.Set<Muscle>().Attach(entity.Muscle);
        }
    }
    DatabaseContext.Set<Exercise>().Add(entity);
    return DatabaseContext.SaveChanges();
}

我正在保存练习。"练习"包含一个名称,"肌肉"设置为有效ID,但不包含任何名称。这就是为什么,当我保存时,验证发生在实体框架内,它告诉我肌肉对象需要名称。

我不需要肌肉完全加载,因为我只想连接这个。我不想在Exercise中有一个属性"MuscleID"。我真的很想有这样的结构。

有人能告诉我我需要做什么才能使验证只发生在保存的实体上,而不发生在外部对象上吗?

实体框架如何使验证仅发生在实体上,而不发生在基础实体上

您应该在控制器和视图之间使用ViewModel。这样你就可以把你的模型排除在等式之外。然后在控制器中使用AutoMapper将ViewModel属性映射到回发时的Model。ViewModel可以定义验证规则并实现IValidatableObject。您还可以将所有ViewModel定义为不具有底层实体。这样可以将多余的实体和属性排除在视图之外。请确保在检查if(ModelState.IsValid)之后使用AutoMapper将ViewModel映射到模型。