为什么ModelState.IsValid返回true但保存更改会抛出DbEntityValidationError?

时间:2015-12-17 15:30:07

标签: asp.net-mvc entity-framework asp.net-mvc-5 entity-framework-6

如果我有两个模型(帖子和评论,其中一个帖子可以有很多评论)和我的邮政控制器,我有一个" LeaveComment"方法...为什么ModelState.IsValid在此方法中返回true,但db.SaveChanges()会抛出DbEntityValidationException?

ModelState.IsValid是否仅检查帖子的有效性,而不检查正在创建的评论的有效性?

我的代码的某些部分如下。

编辑:我也很可能完全采取错误的方法

控制器:

public class PostsController : Controller
{
    private MyEntityModelContainer db = new MyEntityModelContainer();

    [HttpPost, ActionName("LeaveComment")]
    [ValidateAntiForgeryToken]
    public ActionResult LeavePostComment(int? id, string CommentText)
    {
        Post post = db.Posts.Find(id);
        post.LeaveComment(db, CommentText);

        if (ModelState.IsValid)
        {
           //Evaluates to true!

            db.Entry(post).State = System.Data.Entity.EntityState.Modified;
            db.SaveChanges();  //throws DbEntityValidationException
        }
    }
}

评论模型:

public partial class Comment
{
    public Comment () {}

    public Comment(string comment)
    {
        this.CommentText = comment;
    }

    [Required(ErrorMessage="You must enter a comment")]
    public string CommentText { get; set; }

    public virtual Post Post { get; set; }
}

发布模型:

public partial class Post
{        
    public virtual ICollection<Comment> Comments { get; set; }

    public void LeaveComment(MyEntityModelContainer db, string comment_text)
    {
        Comment comment = new Comment(comment_text);
        this.Comments.Add(comment);
    }
}

2 个答案:

答案 0 :(得分:2)

ModelState适用于给定操作的模型。在您的情况下,您没有模型。您只传入一个字符串并使用它来创建模型。你可以查看string.isnullorempty(commenttext)。或者,改为使用模型。

答案 1 :(得分:1)

ModelState是POST数据/ ViewModel的状态,而不是实体模型的状态。 (见http://www.exceptionnotfound.net/asp-net-mvc-demystified-modelstate/)。

要使MVC验证工作,请使用ViewModel作为注释:

public class CommentViewModel : /* optional: */ IValidatableObject {

    [Required(ErrorMessage="You must enter a comment")]
    public string CommentText { get; set; }

    // example how to check for valid ID range
    // this should probably not be nullable if the Id is required by your code
    [Range(1, int.MaxValue)]
    public int PostId { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) {
       // optional: you can put any complex validation logic here ...
     }
}

将您的操作签名更改为

public ActionResult LeavePostComment(CommentViewModel viewModel)

然后ModelState.IsValid将检查ViewModel中的任何验证属性并调用Validate()方法(如果已定义)。