1

我正要开始一个新的宠物项目,我一直想知道在将实体添加到父级的一对多集合时应该如何进行验证。我将使用两个示例类来总结关于 aStudent和 a 的内容Teacher。这里的限制是,在任何给定时间,aStudent只能由一个(并且只有一个)教授,而这个Teacher人又可以教授一个或多个Students)。

public class Student
{
    public bool IsEnrolled { get; set; }

    public virtual Teacher IsCurrentlyBeingTaughtBy { get; set; }
}

public class Teacher
{
    public virtual ICollection<Student> IsCurrentlyTeaching { get; set; }
}

当学生上课时,我需要将他们分配到Teacher'sIsCurrentlyTeaching集合中,但我首先需要确保他们已注册。我的问题是在哪里最好地验证这个基本规则?目前我脑海中的选项是:

1.使用存储库模式

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

2.在控制器动作中验证这一点

我应该在这里提一下,我建议这是一个 MVC3 项目,所以我应该在控制器的操作中执行此验证,然后Student再将Teacher. 但是 - 我是否正在走上一条我真的不应该走的胖控制器路径?

3. 对Teacher实体执行此验证

切断中间人(即存储库)我是否应该Student通过 POCO 上的方法添加,Teacher例如AddStudent(Student student)在尝试添加尚未注册的学生时抛出自定义异常?

可能还有更多可用的选项,但这是我目前试图在这三个之间进行选择的选项,而且我从考虑这个问题中获得了一些狭隘的视野。显然,以上所有内容都可以进行适当的单元测试,但考虑长期(并适应增长)我应该走哪条路?

4

2 回答 2

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; }
于 2013-01-03T17:08:41.453 回答
1

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

以前我创建了一个基类,我的所有派生实体都必须覆盖验证。几乎所有的 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 一样可行。我个人会使用前者,因为这是我的大多数实体目前的样子,“子”实体将自己添加到“父母”中,而不是相反。

于 2013-01-03T16:54:07.290 回答