在entity framework中编辑对象并将其保存到ASP.NET MVC 2.0中的数据库中

所以我知道EF实体跟踪他们自己的更改并在调用savechanges时将它们保存到数据库中,但是这个场景呢……

我有一个旨在编辑博客文章的页面。 它有两种动作方法。

[HttpGet] public ViewResult EditBlogPost(int Id) { //This action method gets the blog post by the id and returns the edit blog post page. BlogPost blogPost = db.BlogPosts.Where(x => x.Id == Id).FirstOrDefault(); if (blogPost == null) { ViewData["message"] = "Blog post not found."; return View("Result"); } return View("ManageBlogPost", blogPost); } [HttpPost] public ViewResult EditBlogPost(BlogPost blogPost) { //This one is where I'm having issues. When model binding populates blogPost, is it auto-tracking still? For some reason SaveChanges() doesn't seem to persist the updates. if (!ModelState.IsValid) return View("ManageBlogPost"); db.AttachTo("BlogPosts", blogPost); //I tried this method, it seemed to be what I wanted, but it didn't help. db.SaveChanges(); ViewData["message"] = "Blog post edited successfully."; return View("Result"); } 

以下是这些回归的观点:

 <%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Master.Master" Inherits="System.Web.Mvc.ViewPage" %>   

Edit Blog Post

Add Blog Post

x.Id)%> x.Date) %> x.Author) %> x.FriendlyUrl) %> Title:
x.Title, new { Style = "Width: 90%;" })%>

Summary:
x.Summary, new { Style = "Width: 90%; Height: 50px;" }) %>

Body:
x.Body, new { Style = "Height: 250px; Width: 90%;" })%>

我在这里有点困惑。 添加博客文章似乎工作正常,但编辑它们是另一回事。

解决方案是不要在编辑操作方法中接受博客文章对象。 相反,做一些看起来像这样的事情:

 [HttpPost] public ViewResult EditBlogPost(int postID) { var post = db.BlogPosts.Single(p => p.PostID = postID); TryUpdateModel(post); if (!ModelState.IsValid) return View("ManageBlogPost"); db.SaveChanges(); ViewData["message"] = "Blog post edited successfully."; return View("Result"); } 

这样,对象附加到上下文,EF可以正确跟踪更改。 UpdateModel方法是一个节省时间的方法,可以自动将表单集合中的字段与模型中的字段进行匹配,并为您更新它们。

以下是UpdateModel的文档: MSDN

entity framework只能跟踪附加到上下文的对象的更改。 上下文生成的对象会自动附加到生成它们的上下文中。 由于您获取的对象是由MVC生成的,因此entity framework不知道哪些值已更新,哪些值尚未更新。

您可以使用几个技巧告诉Entity Framework该项目已被修改。 一种是从上下文中检索实体,在该上下文绑定对象上设置更改的值,然后保存更改。 另一个是做这样的事情来明确告诉上下文的ObjectStateManager某些属性已经改变:

  ///  /// Reattach and mark specific fields on the entity as modified. ///  /// The context to attach the entity object. /// The string representation of the set that should contain the given entity object. /// The detached entity object. /// Names of fields that have been modified. public static void AttachAsModified(this ObjectContext objectContext, string setName, object entity, IEnumerable modifiedFields) { objectContext.AttachTo(setName, entity); ObjectStateEntry stateEntry = objectContext.ObjectStateManager.GetObjectStateEntry(entity); foreach (String field in modifiedFields) { stateEntry.SetModifiedProperty(field); } } 

我的团队最终开发了一个框架,该框架自动从上下文加载对象,找出哪些属性与传入的新属性不同,并将这些属性设置为未附加对象提供的值。 这种方法也值得为您考虑。 有可能像AutoMapper这样的东西可以为你做这件事,但我不确定。

编辑

Shea提到使用控制器的UpdateModel方法有效地推迟属性值的设置,直到从上下文中检索实体对象为止。 这对我来说听起来像是一种好的方法(假设你在控制器中有数据访问代码就可以了),但是你可能想要使用覆盖来实现它,这样你仍然可以让方法绑定到同一个对象类型:

 [HttpPost] public ViewResult EditBlogPost(BlogPost blogPost) { //This one is where I'm having issues. When model binding populates blogPost, is it auto-tracking still? For some reason SaveChanges() doesn't seem to persist the updates. if (!ModelState.IsValid) return View("ManageBlogPost"); var dbPost = db.BlogPosts.Single(bp => bp.BlogPostId = blogPost.Id); UpdateModel(dbPost, "blogPost"); db.SaveChanges(); ViewData["message"] = "Blog post edited successfully."; return View("Result"); }