使用Entity Framework时,处理ASP.NET MVC中的必填字段

Che*_*hev 7 c# validation asp.net-mvc entity-framework asp.net-mvc-3

好吧,这个问题真的在我的皮肤下.让我从一步一步的格式描述我的应用程序开始.

首先,我有我的Entity Framework生成的模型.在其中我有以下实体:

http://www.codetunnel.com/EFEntities.jpg

现在,为了在实体上实现验证,我使用了部分类并处理EF提供的OnChanging挂钩.以下是PostComment部分类的示例:

namespace CodeTunnel.Domain.Models
{
    public partial class PostComment : IDataErrorInfo
    {
        private Dictionary<string, string> _errors = new Dictionary<string, string>();

        partial void OnAuthorChanging(string value)
        {
            //Validating anything but required value works fine.
            //Like this pseudo-validator.
            if (value.ToLower() != "fred")
                _errors.Add("Author", "Sorry, your name must be Fred.");
        }

        partial void OnBodyChanging(string value)
        {
            //Required value validation does not work, I will tell you why below.
            if (string.IsNullOrEmpty(value))
                _errors.Add("Body", "Body is required.");
        }

        #region -= IDataErrorInfo methods =-

        public string Error
        {
            get { return string.Empty; }
        }

        public string this[string columnName]
        {
            get
            {
                if (_errors.ContainsKey(columnName))
                    return _errors[columnName];
                return string.Empty;
            }
        }

        #endregion
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,我的类继承自IDataErrorInfo.默认情况下,MVC会检查此错误.如果它找到任何,则它使模型无效并使用存储的错误作为视图中验证助手的消息.我很确定当EF抛出一个异常时,这个字典甚至永远不会填充该属性的值.事实上,我甚至不确定MVC是否在EF生成异常后检测并使模型无效时查找值.

这是问题的屏幕截图,包括示例伪验证器,因此您可以看到它正在工作:

http://www.codetunnel.com/ValidationError.jpg

如您所见,错误消息未显示.但是,它确实将该字段验证为无效.如果我在那里放一个值,那么它验证就好了.我已经对这个问题进行了很多研究,这就是我所知道的:

您无法自定义为必填字段显示的错误消息的原因是因为model属性不可为空.因为它不可为空,所以尝试将null值绑定到它会引发异常.MVC吞下了这个例外,并使模型无效.在发生此异常的任何地方都会生成消息.我不知道消息是由EF还是MVC生成的(我猜MVC因为它首先负责吞下异常).我不知道如何自定义此消息.正如你所看到的,它总是说"价值''是无效的." 我认为这并不完全可怕,但它真的不是非常用户友好.

它到达我的名称验证器并检查你的名字是否"fred"就好了,因为没有抛出任何异常.就EF而言,传入的价值是可以的.直到它达到我的OnAuthorChanging方法它才意识到它不合适.这是正确的行为,并且工作得很好.

如果我在OnChanging事件中抛出异常而不是添加到我的IDataErrorInfo字典中,我可以生成相同的验证消息,只有它将输入的值放在单引号之间.例:

    partial void OnAuthorChanging(string value)
    {
        if (value.ToLower() != "fred")
            //_errors.Add("Author", "Sorry, your name must be Fred.");
            throw new Exception("Sorry, your name must be Fred.");
    }
Run Code Online (Sandbox Code Playgroud)

当输入"test"作为Author的值时,该代码显示此消息:"值'test'无效.".对于必填字段,它只是值为null,因此单引号之间没有任何内容.

有些人(比如这个人)建议你只需在你的模型中将属性设置为可空.这不是一个可接受的解决方案.其中一个原因是:

错误3031:从第313行开始映射片段的问题:不可为空的列PostComments.Body in Table PostComments映射到可空的实体属性.

另外,设置nullable对于非可空类型(例如int)不起作用,将int切换为可空int是一个令人讨厌的混乱,我甚至不会进入这里.

最重要的是,我想从EF自己处理这些例外,或者至少自定义它生成的消息,但我不知道如何.我完全迷失了.我想要做的就是根据我认为非常简单的模型验证定制一条消息!

任何帮助深表感谢.

小智 8

正如您所发现的,MVC正在基于不可归类型来验证您的模型.这是在自定义验证运行之前向ModelState添加错误.

我之前有过这个,并通过在动作开始时循环通过Modelstate并删除所有内容,然后进行自定义验证(坏!!)来解决它

然后发现即使您没有使用数据注释作为主要验证形式,您也可以通过添加[对buddy类中的非nullible类型是必需的,并指定消息来自定义抛出的消息.

它是这样的:

[MetadataType(typeof(YourClassMetadata))]
public partial class YourClass
{       
  //buddyclass to entity class
  class YourClassMetadata 
  {
    [Required(ErrorMessage="Your custom overriding error message")]
    public int NonNullablePropertyThatIsGivingYouProblems {get;set;}
  }
}
Run Code Online (Sandbox Code Playgroud)

我已经开始为mvc 查看流畅的验证(http://fluentvalidation.codeplex.com),他们似乎通过添加行来关闭global.asax中的问题,在application_start()上

DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;
Run Code Online (Sandbox Code Playgroud)

但我可能错了.