我应该在哪里验证添加到我的实体的集合属性?

时间:2013-01-03 16:20:08

标签: c# asp.net-mvc-3 entity-framework repository-pattern

我正准备开始一个新的宠物项目,我一直想知道在向父母的一对多集合添加实体时我应该如何进行验证。我将使用两个示例类来总结我对StudentTeacher的看法。这里的约束是,在任何给定时间,Student只能由一个(并且只有一个)Teacher教授,而Student反过来可以教授一个或多个public class Student { public bool IsEnrolled { get; set; } public virtual Teacher IsCurrentlyBeingTaughtBy { get; set; } } public class Teacher { public virtual ICollection<Student> IsCurrentlyTeaching { get; set; } } s。

Teacher

当学生到达课程时,我需要将它们分配到IsCurrentlyTeaching的{​​{1}}集合,但我首先需要确保他们已注册。我的问题是哪里最好验证这个基本规则?我目前的选择是:

1。使用存储库模式

由于我将要应用单元测试,所以我倾向于支持这种方法,因为我可以将我的数据访问逻辑包装到一个可模拟的对象中,这里只有一个责任所以我只需要在我的存储库一次。但是 - 验证存储库的责任,还是我应该只处理存储库中实体的CRUD?

2。在控制器操作中验证

我在这里应该提一下,我建议将它作为一个MVC3项目,因此我应该在控制器的操作中执行此验证,然后将Student添加到存储库(以及随后的{{1他们目前正在教授的学生名单。但是 - 我正沿着fat controller路走下去,我真的不应该这样做吗?

第3。在Teacher实体

上执行此验证

切断中间人(即存储库)我应该通过Teacher POCO(例如Student)上的方法添加Teacher并在尝试添加时抛出自定义异常还没有注册的学生?

可能有更多的选择,但这些是我现在想要在这个时刻之间做出选择的三个选项,并且我从思考这个问题得到了一点隧道视野。显然,以上所有都可以进行适当的单元测试,但是考虑长期(并且适应增长)我应该走哪条路?

2 个答案:

答案 0 :(得分:2)

您可以为此创建自己的自定义验证器。那会让你捎带MVC已经提供的验证。我从来没有尝试过这个,但我会想象这样的事情会起作用:

public class EnsureEnrollment : ValidationAttribute
{
    public EnsureEnrollment () {    }

    public override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var studentList = value as IEnumerable<Student>;
        if (studentList == null)
        {
            return ValidationResult.Success;
        }

        foreach(Student s in studentList )
        {
            if(!s.IsEnrolled)
            {
                //Insert whatever error message you want here.  
                return new ValidationResult("Student \"" + s.Name + "\" is not enrolled.");
            }
        }

        return ValidationResult.Success;
    }
}

然后在你的属性上添加你的注释:

[EnsureEnrollment()]
public virtual ICollection<Student> IsCurrentlyTeaching { get; set; }

答案 1 :(得分:1)

就个人而言,我喜欢在我的实体上将我的验证作为静态CRUDL方法的一部分。确实,您必须将上下文传递给它们中的每一个,但它使控制器更加清晰,并使所有这些功能随时可用于将来可能使用您的实体的任何其他项目。

之前我创建了一个基类,我的所有实体都派生自该类,必须覆盖Validate。几乎所有的CRUDL方法和其他工作方法都调用了Validate方法,以确保实体在采取行动之前是正确的。大多数验证规则都比较复杂,可以使用DataAnnotations属性轻松表达。

或者您可以将特定验证点集成到具有更特定目的的方法中。举个例子:

    public static bool AddToTeacher(SchoolContext db, Student student, Teacher teacher)
    {
        if (student.IsEnrolled)
        {
            teacher.IsCurrentlyTeaching(student);
            return db.SaveChanges() > 0;
        }
        return false;
    }

AddToTeacher方法仅确保满足特定要求。如果我想确保学生正确形成并且符合条件的课程,那么我可能会写一个简短的方法(或几个所谓的“容器”方法)来验证这些特定点。

简而言之,我会尽力在实体上保留每一个特定于实体的代码,以便控制器基本上不了解实体的工作方式。

至于哪个实体,它取决于你的想法。在我看来,Student.AddToTeacher和Teacher.AddStudent一样可行。我个人会使用前者,因为这是我的大多数实体目前看起来像“子”实体将自己添加到“父母”而不是相反的方式。