簡體   English   中英

在實體框架中編輯對象並將其保存到ASP.NET MVC 2.0中的數據庫中

[英]Editing an object in entity framework and saving it to the database in 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<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>

我在這里有點困惑。 添加博客文章似乎工作正常,但編輯它們是另一個故事。

解決方案不是在編輯操作方法中接受博客文章對象。 相反,做一些看起來像這樣的事情:

[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

實體框架只能跟蹤附加到上下文的對象的更改。 上下文生成的對象會自動附加到生成它們的上下文中。 由於您獲取的對象是由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");
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM