MVC - 验证 - ViewModel应该可以访问DB

时间:2013-11-08 13:19:25

标签: c# asp.net-mvc validation asp.net-mvc-4

我有一个视图模型应检查新实体的标签是否唯一(不在DB中)。

目前我已经在视图模型类中完成了它:

     public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (PowerOrDuty != null)
        {
            if (PowerOrDuty.Identifier == null)
            {
                using (var db = new PowersAndDutiesContext()) 
                {
                    var existingLabels = db.PowersAndDuties.Select(pod => pod.Label);
                    if (existingLabels.Contains(PowerOrDuty.Label))
                    {
                        yield return new ValidationResult("Cannot create a new power or duty because another power or duty with this label already exists");
                    }
                }                    
            }
           ......

请注意,这是一个小型内部应用程序,小数据库,我的时间有限,所以代码并不完美。

我觉得从视图模型访问数据库可能是一种不好的做法。视图模型是否应该直接访问数据库?它应该能够调用存储库来获取可用的标签吗?是否应该在控制器中进行需要DB访问的验证?

4 个答案:

答案 0 :(得分:6)

  

视图模型是否应该直接访问数据库?

我认为应该不惜一切代价避免这种情况

  

它是否应该能够调用存储库来获取可用的标签?

这不是ViewModel的关注点。 这会在ViewModel的测试中引入一些复杂性(几乎不需要),我想这是一个麻烦来临的迹象。

  

是否需要在控制器中进行需要DB访问的验证?

也许,如果用“DB”表示“存储库”。但是我想到的是一个单独的自定义验证类,您可以在另一个控制器中进行插件,测试和重用,以进行ajax验证等。

答案 1 :(得分:1)

我个人认为ViewModel是贫血的 - 只是具有属性的类。

对于像这样的自定义服务器端验证,我更喜欢它在服务中,在控制器中消耗服务,甚至在自定义验证器后面。

使用自定义验证器,您甚至可以(可选)远程执行验证。虽然这有点复杂,但我使用通用的远程验证器来完成它,它使用Ajax操作方法来执行验证,并通过客户端验证器和远程验证器连接(以确保您拥有验证逻辑)用一种方法)。

但是,无论你走到哪一步,我认为更常见 - 而且在我看来,更干净 - 让所有逻辑都远离你的ViewModel。即使在一个简单的应用程序中,您的ViewModel也应该对您的数据库上下文愚蠢。理想情况下,只有服务(不一定是Web服务,而只是一个抽象层)才能了解您的数据库上下文。

对我而言,无论应用程序的大小如何,都应该这样做。我认为努力和复杂性(它只为您的解决方案添加了另一个程序集)值得您获得的抽象。在路上,如果你碰巧决定从另一个应用程序中使用你的服务,或者你决定换掉你的数据库上下文,那么抽象就好了。

答案 2 :(得分:1)

您的视图模型不应与您的上下文相关联,它只关注在提交后显示数据和验证数据。您可以执行验证,如必填字段或范围内的值,但您无法知道数据库中是否已存在标签。

在显示表单之前,您无法获取“禁止标签”列表,以便之后测试您的标签,因为该列表在此期间可能已更改(另一位用户更新您的数据库)。

在我看来,模型级别的验证应该关注它可以在不知道数据源的情况下验证的内容,并让您的数据库通知您在具有唯一约束的字段中提交重复值等错误。您将捕获来自数据库的异常以查找类似的错误,并相应地管理它们。

无论如何,我认为对于像这样的问题没有直接的答案。

答案 3 :(得分:0)

我认为从VM访问数据库并没有错... AFAIK它没有打破MVC概念(因为它是一个表示层概念)。说,如果你有服务层提供的Validate方法可能会更好。

但是所有与ViewModel内容相关的逻辑,最好保存在VM中而不是Controller中。清洁控制器更好。