【问题标题】:Editing an object in entity framework and saving it to the database in ASP.NET MVC 2.0在 ASP.NET MVC 2.0 中编辑实体框架中的对象并将其保存到数据库中
【发布时间】:2011-06-28 17:16:57
【问题描述】:

所以我知道 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<BlogProject.Models.BlogPost>" %>

<asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">

    <% if (Model != null)
       { %>
            <h2>Edit Blog Post</h2>
    <% }
       else
       { %>
            <h2>Add Blog Post</h2>
    <% } %>
    <% using (Html.BeginForm())
       { %>
            <% if (Model != null)
               { %>
                    <%: Html.HiddenFor(x => x.Id)%> <!-- Is this the way to keep un-editable data hidden from the edit form and have them repopulate on the next model bind? What if someone went to modify their POST using something like Fiddler? Couldn't they theoretically edit these fields before the POST? -->
                    <%: Html.HiddenFor(x => x.Date) %>
                    <%: Html.HiddenFor(x => x.Author) %>
                    <%: Html.HiddenFor(x => x.FriendlyUrl) %>
            <% } %>
            Title:<br />
            <%: Html.TextBoxFor(x => x.Title, new { Style = "Width: 90%;" })%>
            <br />
            <br />
            Summary:<br />
            <%: Html.TextAreaFor(x => x.Summary, new { Style = "Width: 90%; Height: 50px;" }) %>
            <br />
            <br />
            Body:<br />
            <%: Html.TextAreaFor(x => x.Body, new { Style = "Height: 250px; Width: 90%;" })%>
            <br />
            <br />
            <input type="submit" value="Submit" />
    <% } %>

</asp:Content>

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

【问题讨论】:

    标签: c# asp.net-mvc entity-framework asp.net-mvc-2 entity-framework-4


    【解决方案1】:

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

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

        /// <summary>
        /// Reattach and mark specific fields on the entity as modified.
        /// </summary>
        /// <param name="objectContext">The context to attach the entity object.</param>
        /// <param name="setName">The string representation of the set that should contain the given entity object.</param>
        /// <param name="entity">The detached entity object.</param>
        /// <param name="modifiedFields">Names of fields that have been modified.</param>
        public static void AttachAsModified(this ObjectContext objectContext, string setName, object entity,
                                            IEnumerable<String> 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");
    }
    

    【讨论】:

    • 好的,那么如何将对象附加到上下文中?
    • @Chevex:您已经将对象附加到上下文,但是您是在设置属性值之后执行此操作,因此上下文不知道它们已被更改。有关如何解决此问题的一些想法,请参阅我的编辑。
    • 感谢您的建议。我将数据访问代码放在控制器中以简化此问题中的代码。在实际实现中我使用存储库模式来检索数据,所以这里没有违反关注点分离:) +1 求助!
    【解决方案2】:

    解决方法是不要在你的编辑操作方法中接收博客文章对象。相反,请执行如下所示的操作:

    [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

    【讨论】:

    • 不,请查看 MS 的示例。 UpdateModel 方法仍在为您完成繁重的工作。
    • 哦,这消除了对所有隐藏字段(id 除外)的需要,不是吗!因为我是从上下文中提取对象,然后更新它,所以我不需要担心填充对象上的不可编辑字段对吗?
    • 我不知道你的具体情况,但我认为你是对的。这是文档:msdn.microsoft.com/en-us/library/dd470185.aspx
    • 查看我在视图页面中的评论,询问隐藏字段是否是存储下一篇文章和模型绑定信息的正确方式。
    • 是的,我认为使用这种方法可以避免使用隐藏字段。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-06-22
    • 2016-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多