【问题标题】:How to validate entity against the context in Entity Framework?如何根据实体框架中的上下文验证实体?
【发布时间】:2018-08-11 01:16:48
【问题描述】:

我通常通过调用 entity.IsValid() 并为实体创建适当的 ValidationAttribute 类来验证实体框架中的实体。

但是,现在我遇到了一个案例,我不仅需要验证实体,还需要在它所属的上下文中验证实体,例如:

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class CourseValidation : ValidationAttribute
{
    public CourseValidation() {}
    protected override ValidationResult IsValid (object value, ValidationContext validationContext)
    {
        List<string> messages = new List<string>();
        if (value is Course)
        {
            Course course = (Course)value;
            if (course.Context != null)
            {
                if (course.Context.Courses.Any(c => c.Name == course.Name && c.Department.ID == course.Department.ID))
                {
                    messages.Add($"Cannot create a course with name {course.Name} in {course.Department.Name} department because a course with this name already exists in this department.");
                }
            }
            else messages.Add("Course is being improperly handled by the software, please contact support department");
         }
         else messages.Add("Course is expected, but does not exist");

         if (messages.Count > 0) return new ValidationResult(string.Join(Environment.NewLine, messages));
         else return ValidationResult.Success;
     }
}

有一个困难:简单地使用context.Courses.Add(course) 不会导致context.Courses.Where(c =&gt; c.Name == course.Name) 返回任何东西。相反,它需要context.SaveChanges() 才能将实体作为整个集合的一部分使用。这意味着在尝试将实体保存到数据库之前,我将无法针对集合验证实体。

我知道这个示例很简单,可以通过数据库端唯一约束来处理,但即使我们不打算查看更复杂的示例,我也有充分的理由在尝试提交之前过滤无效条目它们到数据库(因为如果事务中的一个条目违反约束,整个事务将被阻止),并将所有验证标准放在一个地方,而不是在不同的类和/或数据库模式之间拆分它们(以维护单一责任)。

可以通过哪些方式实施验证策略来满足这些要求?

【问题讨论】:

    标签: c# .net entity-framework validation


    【解决方案1】:

    我们所做的是覆盖上下文的ValidateEntity method。这使您有机会在提交更改之前检查数据库中的内容(如重复项等)。

    只需将覆盖的类添加到您的上下文中并执行您需要的任何检查:

    protected override DbEntityValidationResult ValidateEntity(DbEntityEntry entityEntry,
        IDictionary<object, object> items)
    {
    
        if (entityEntry.Entity is Course &&
                    (entityEntry.State == EntityState.Added 
                      || entityEntry.State == EntityState.Modified))
        {
            var courseToCheck = ((Course)entityEntry.Entity);
    
            //check for uniqueness 
            if (Courses.Any(c => c.Name == course.Name && c.Department.ID == course.Department.ID)))
                return 
                       new DbEntityValidationResult(entityEntry,
                     new List<DbValidationError>
                         {
                             new DbValidationError( "Name",
                                 $"Cannot create a course with name {courseToCheck .Name} in {courseToCheck .Department.Name} department because a course with this name already exists in this department.")
                         });
        }
    
        return base.ValidateEntity(entityEntry, items);
    }
    

    现在您可以致电context.GetValidationErrors() 并在保存前处理错误。例如here

    【讨论】:

    • 谢谢你,史蒂夫,这绝对有道理,我一回家就试试。
    • 谢谢,一切正常。需要添加的一件事是检查Courses.Local.Any(c =&gt; c.Name == course.Name &amp;&amp; c.Department.ID == course.DepartmentID),因为在SaveChanges() 之前,由于某种原因,通过寻址原始集合不会返回添加的实体。
    猜你喜欢
    • 2011-04-14
    • 2010-09-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-06
    相关资源
    最近更新 更多