【问题标题】:ASP.Net MVC3 missing model propertiesASP.Net MVC3 缺少模型属性
【发布时间】:2012-07-03 22:27:37
【问题描述】:

我是 MVC3 的新手,正在尝试编写一个博客应用程序作为学习工具。

我为博文创建了一个数据库对象,并使用带有读/写操作的控制器生成了一个控制器,并使用 Entity Framework 来控制实体。

我在使用编辑命令时遇到问题。一篇博客文章大约有 6 个属性,但我只想允许编辑来修改文章的标题和内容。我的代码如下:

public ActionResult Edit(int id)
    {
        blog_Post blog_post = db.blog_Post.Find(id);
        return View(blog_post);
    }

    //
    // POST: /Post/Edit/5

    [HttpPost]
    public ActionResult Edit(blog_Post blog_post)
    {
        if (ModelState.IsValid)
        {
            db.Entry(blog_post).State = EntityState.Modified;
            db.SaveChanges();
            return RedirectToAction("Index");
        }
        return View(blog_post);
    }

@model BlogVersion1._0.blog_Post

@{
    ViewBag.Title = "Edit";
}

<h2>Edit</h2>

@using (Html.BeginForm()) {
@Html.ValidationSummary(true)
<fieldset>
    <legend>blog_Post</legend>

    <div class="editor-label">
        @Html.LabelFor(model => model.Title)
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => model.Title)
        @Html.ValidationMessageFor(model => model.Title)
    </div>

    <div class="editor-label">
        @Html.LabelFor(model => model.PostContent)
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => model.PostContent)
        @Html.ValidationMessageFor(model => model.PostContent)
    </div>

    <p>
        <input type="submit" value="Save" />
    </p>
</fieldset>
}

<div>
@Html.ActionLink("Back to List", "Index")
</div>

出现的问题出在公共 ActionResult Edit(blog_Post blog_post) 方法中。在 Edit(int id) 方法中,我设置了一个断点,我可以看到 blog_post 被正确地传递给了视图(包括所有填充的属性)。

但是返回到 [HttpPost] 方法的 blog_post 缺少 UserId、DateCreated 等属性。由于缺少所需的外键,db.SaveChanges 调用显然会引发异常。

如何确保所有属性都返回到第二个编辑方法以正确进行更新?

【问题讨论】:

    标签: c# sql-server asp.net-mvc-3 entity-framework


    【解决方案1】:

    因为当您执行 POST 时,您没有从表单中发送这些元素的值。解决此问题的一种方法是使用 Hidden 变量将它们保留在表单中

    @using(Html.BeginForm())
    {
      @Html.EditorFor(model => model.Title)
      @Html.HiddenFor(model => model.UserId)
      <input type="submit" />
    }
    

    我认为干净的解决方案是“不要在视图中使用域模型,使用具有 necessary 属性的视图模型。在这种情况下,显然 CreatedDate 不应该是视图应该供应。它应该是代码将填充到对象的东西。

    所以为此创建一个 ViewModel

    public class BlogPostViewModel
    {
      public int ID { set;get;}
      public string Title { set;get;}
      public string Description { set;get;}  
    }
    

    并使用它来将数据从视图传输到控制器,反之亦然

    public ActionResult Edit(int id)
    {
      var domainObject=repo.GetPost(id);
      var viewModel=new BlogPostViewModel();
      viewModel.ID=domainObject.ID;
      viewModel.Title=domainObject.Title;
     //map other REQUIRED properties also
      return View(viewModel);
    }
    

    您的视图将被强类型化到此

    @model BlogPostViewModel
    @using(Html.BeginForm())
    {
      @Html.EditorFor(model => model.Title)
      @Html.HiddenFor(model => model.Description)
      <input type="submit" />
    }
    

    在 POST 动作中,将其映射回域对象并保存

    [HttpPost]
    public ActionResult Edit(BlogPostViewModel model)
    {
     if(ModelState.IsValid)
     {
       var domainObject=new blog_Post();
       domainObject.Title=model.Title;
    
       domainObject.ModifiedDate=DateTime.Now;
       //set other properties also
    
       repo.Update(domainObject);
       return RedirecToAction("Success");
     }
     return View(model);
    }
    

    您可以考虑使用AutoMapper 库,而不是一一手动映射属性,它可以在一行代码中为您完成这项工作!

    【讨论】:

      【解决方案2】:

      只需为所有其他不可编辑的属性添加隐藏字段。

      @Html.HiddenFor(model => model.Id)
      

      这些字段将包含在 POST 中,因此模型绑定器会正确地将它们放入您的 blog_post 实例中。

      另一方面,您应该真正使用视图模型——简单的 POCO 类将成为您的视图的模型。不建议直接使用实体模型。

      以下是一些相关信息:
      ASP.NET MVC ViewModel Pattern
      http://stephenwalther.com/archive/2009/04/13/asp-net-mvc-tip-50-ndash-create-view-models.aspx

      【讨论】:

        【解决方案3】:

        模型绑定器只会填充在 HTTP 请求中发布的属性。您的视图仅包含 Title 和 PostContent。

        您需要为每个缺失的属性添加隐藏字段。或者只是 ID 属性,然后对其余部分进行数据库查找。

        【讨论】:

          【解决方案4】:

          对于您的情况,我认为您应该使用 HtmlHelper 扩展方法“EditorForModel”而不是为每个属性调用“EditorFor”。您在每个属性上使用 EditorFor 使您的生活变得复杂(正如 gred84 所说,它不会在您的上下文中的 HTTP 请求中发布未显示的属性)。

          在您的 blog_Post 模型类中,您应该使用属性 [HiddenInput(DisplayValue = false)] 标记您不想编辑的每个属性

          然后,您可以简单地拥有(简化 - 没有验证摘要)

          ,而不是视图中的所有代码
          @using (Html.BeginForm())
          {        
             @Html.EditorForModel()
             <input type="submit" value="Save" />   
          } 
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2012-03-14
            • 2018-02-16
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-06-25
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多