【问题标题】:MVC3 - Why are navigation properties null on postbackMVC3 - 为什么回发时导航属性为空
【发布时间】:2012-07-10 23:01:30
【问题描述】:

我不知道如何在我发布后让我的模型 (EF4) 的导航属性不为空。我在几个基本页面上遇到了同样的问题。

即我有一张桌子 估计 外键为 LoginID(来自 Login 表)。

在我的 HTTPGet Edit 方法中,我找到了我想要的具体估算:

Estimate estimate = db.Estimates.Find(id)

从这里我可以访问登录导航属性以及登录表中该记录的任何属性。

我将此估计作为强类型视图的模型传递。当我的 HTTPPost Edit 方法被调用(并且模型作为参数传递给它)时,我的 Login 导航属性为空,我无法访问其中的任何内容。我当然可以绕过它,因为我的估算类中确实有 LoginID 字段,但感觉真的很笨重,就像我错过了实体框架的一个关键好处。

我在多个页面上遇到了同样的问题,我将带有导航属性的模型传递给我的视图,而视图正在返回带有空导航属性的模型。

下面是我遇到问题的代码示例:

    [HttpPost]
    public ActionResult Edit(Estimate estimate)
    {

        var test = estimate.Login.CompanyProfileID;
        ...

我可以在视图中访问 Model.Login 及其所有属性,因此我知道它已正确传递给视图。当我的表单提交时,它只是不会将导航属性传递回控制器。

【问题讨论】:

  • 你能发布视图和模型代码吗?
  • 您的视图是否绑定到导航模型或者您有一些视图模型,这就是为什么您需要向我们展示您的视图代码

标签: asp.net-mvc-3 entity-framework


【解决方案1】:

发生的情况是 MVC 使用了一种称为“模型绑定”的东西,它将 POST 在页面请求中传递的所有字段与您的操作参数的匹配属性相匹配。

因此,如果该属性未包含在POST 页面的输入字段中,则它不会绑定到您的POST 操作中的参数,因此将为空。

因此,您可以为 Login 中的每个属性添加一个隐藏字段,例如

@Html.HiddenFor(m => m.Login.ID)
@Html.HiddenFor(m => m.Login.Name)

或者,就像您在解决方法中描述的那样 - 即根据 Id 重新查询数据库。虽然这可能看起来很笨重,但这是一种非常有效的做事方式,因为它避免了到处传递隐藏字段。

【讨论】:

  • 好吧,我想我会继续做我当时正在做的事情。现在说得通了。感谢您的解释。我有我的模型和外键可用,但必须重新查找导航属性,这感觉不对。
  • 一旦您更习惯于使用 MVC,并更好地熟悉“Web 的无状态本质”以及它如何通过请求和响应来工作,这种方法将开始感觉更自然.
  • 多对多属性呢?我试过@Html.HiddenFor(m => m.aListProperty.ToList()) 但不允许
  • @Kevin 绑定到列表属性一直很棘手。达林对此here给出了很好的解决方案
  • 我尝试了隐藏变量的解决方案,但是值是空的,因为导航属性没有值,当你插入一个新值时我该怎么办?也许通过 javascript 或其他方式填充隐藏变量...感谢您的帮助
【解决方案2】:

您返回的 Estimate 对象受视图字段的限制(以及任何任何 Bind 属性)。为您想要的属性添加隐藏字段或从上下文重新加载对象。

注意事项(我将这个答案发布到一个长期死问题的全部原因)是对于 EF6,如果您在部分 EntityState.Modified 上的 .SaveChanges 之后从上下文重新加载对象(因为您正在聪明)它将为您提供实体的缓存和不完整版本。您必须执行 context.Entity(estimate).Reload() 而不是 .Find 或 .Where

【讨论】:

    【解决方案3】:

    MVC 没有任何视图状态或视图中自动持久化数据的概念。您希望通过 POST 返回给您的任何属性都必须作为表单字段存在于表单中。在这种情况下,您需要一个隐藏字段来存储 LoginID

    @Html.HiddenFor(m => m.LoginID)
    

    【讨论】:

    • 我的表单中已经有 @Html.HiddenFor(model => model.LoginID) 。实际的 LoginID 属性在帖子中,但导航属性“Login”(链接到该 LoginID)为空。如何在帖子中也提供导航属性?
    【解决方案4】:

    我有类似的情况,在后期操作中,我从数据库中提取原始项目,然后根据我需要做什么,将所有编辑的属性复制到我拉出的项目并使用复制的属性保存原始项目(那些可能由用户编辑),或者用缺失的属性填充发布的模型,然后保存它。我不确定这是否是正确的做法,但它对我有用。当您从数据库中提取原始项目时,您可以访问您想要的任何属性(假设用户无法更改它)。

    例子:

     [Authorize]
            public ActionResult Edit(int id)
            {
                var movie = movieService.GetMovieById(id);
                if (new UserService().Current().UserId == movie.UserID)
                {
                    EditMovieModel model = new EditMovieModel(id);
                    return View(model);
                }
                else
                {
                    throw new System.Web.HttpException(403, "403 Forbidden");
                }
            }
    
            [HttpPost]
            [Authorize]
            public ActionResult Edit(Movie movie)
            {
                var realMovie = movieService.GetMovieById(movie.ID);
                if (new UserService().Current().UserId == realMovie.UserID)
                {
                    realMovie.Text = HtmlSanitizer.sanitize(movie.Plot);
                    realMovie.CategoryID = movie.CategoryID;
                    movieService.Update(realMovie);
                }
                else
                {
                    throw new System.Web.HttpException(403, "403 Forbidden");
                }
                return RedirectToAction("Movie", new { id = realMovie.ID, title = realMovie.Permalink });
            }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-05-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-13
      相关资源
      最近更新 更多