MVC3 - 为什么回发时导航属性为null

时间:2012-07-10 23:01:31

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

在发布后,我无法弄清楚如何让我的模型(EF4)的导航属性不为null。我在几个基本页面上遇到了同样的问题。

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

在我的HTTPGet编辑方法中,我找到了我想要的具体估计值:

Estimate estimate = db.Estimates.Find(id)

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

我将此估算值作为我的强类型视图的模型。当我调用HTTPPost Edit方法(并将模型作为参数传递给它)时,我的Login导航属性为null,我无法访问其中的任何内容。我当然可以解决这个问题,因为我的估计课程中确实有LoginID字段,但感觉非常笨重,而且我错过了实体框架的一个关键优势。

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

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

    [HttpPost]
    public ActionResult Edit(Estimate estimate)
    {

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

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

4 个答案:

答案 0 :(得分:6)

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

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

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

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

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

答案 1 :(得分:0)

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

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

答案 2 :(得分:0)

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

示例:

 [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 });
        }

答案 3 :(得分:0)

您回来的估算对象受视图字段(以及任何任何Bind属性)的限制。为所需属性添加隐藏字段或从上下文重新加载对象。

请注意(我将这个答案发布给一个长期存在的问题的全部原因)是对于EF6,如果在部分EntityState.Modified上的.SaveChanges之后从上下文重新加载对象(因为你)它很聪明)它会给你一个CACHED和未完成的实体版本。你必须做一个context.Entity(估计).Reload()而不是.Find或.Where