System.Web.MVC.UpdateModel能否更新EF导航属性?

4
如果我的数据库中有两个表:Foo和bar。Foo由FooId标识,而Bar由BarId标识。一个Bar可以有0到多个Foos,因此Foo具有BarId作为外键。我有一个代表此的模型和一个视图,可用于编辑Foo并选择(从下拉列表中)相关联的Bar。
给定控制器上的以下方法:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(int id, FormCollection formCollection)
{
    Foo originalFoo = FooById(id);

    if (!ModelState.IsValid)
    {
        return View(new VenueViewModel(originalVenue, _db.GetCounties(), _db.VenueTypeSet));
    }

    UpdateModel(originalFoo);

    /* Instead of using UpdateModel I could just iterate through 
       formCollection and manually update originalFoo, it would 
       work but surely there is a better way? */

    _db.SaveChanges();

    return RedirectToAction("Index");
}

UpdateModel的调用会抛出一个没有InnerExceptionInvalidOperationException异常:

The model of type 'TestApplication.Models.Foo' was not successfully updated.

我的控制器应该如何从视图中的下拉菜单更新基于Entity Framework的模型?
1个回答

7
不, 默认的模型绑定器不能做到这一点。你很难编写一个自定义的模型绑定器来完成它。HTML SELECT元素只会在描述中存储一个ID值,这对于大多数实体实例来说是不足够的。因此,我们只能接受这样一个事实,即我们只能得到一个ID,这对于不经过数据库就无法实现实体化的实体来说是不够的。
因此,在更新实体的导航属性时,我们有两个选择:
1.从数据库中读取实体,并将其分配给控制器中的导航属性。 2.不尝试为导航属性实体实现实体化;而是直接将EntityKey分配
后者是我所做的。你可以在自定义模型绑定器或控制器中执行此操作。你可以在链接中阅读更多关于此操作的内容,并且我在该链接的评论中提供了一些示例代码。
在即将发布的.NET 4.0中,Entity Framework的新版本将拥有一个称为“FK Associations”的新特性,这将使此过程变得更加容易。

.NET的新版本(4.0)与EFv4确实将外键引入实体,但如果我们在视图中使用EditorFor()并为我们的类型使用强类型的自定义模板,则默认模型绑定程序会成功地将导航属性的属性绑定到来自EditorFor模板的POSTed值。然而,这仍然不足以使上下文中的SaveChanges()工作。它会出现错误,要么是1)主键已经存在,要么是2)无法更改相关实体的主键(我们实际上没有更改它),但还是会出错。 - mare
默认绑定器跳过外键属性,因此我们只能手动设置此属性并将导航属性设置为null。然后它就可以工作并保存更改。 - mare
难道不能将模型绑定器与对象附加一起使用吗?例如,如果下拉列表的名称为“'Bar.Id'”,并且您让模型绑定器从表单创建一个Foo元素(称其为myNewFoo),它会填充myNewFoo.Bar.Id。然后,您不能调用db.BarTable.Attach(myNewFoo.Bar);吗? - Flater

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接