Редактирование объекта в Entity Framework и сохранение его в базе данных в ASP.NET MVC 2.0 - PullRequest
8 голосов
/ 17 февраля 2011

Итак, я знаю, что сущности 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>

Я немного запутался здесь. Добавление сообщений в блог, кажется, работает нормально, но редактирование их - это другая история.

Ответы [ 2 ]

7 голосов
/ 17 февраля 2011

Решение не состоит в том, чтобы использовать объект сообщения блога в вашем методе действия редактирования.Вместо этого сделайте что-то похожее на это:

[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

2 голосов
/ 17 февраля 2011

Entity Framework может отслеживать изменения только для объектов, которые прикреплены к контексту. Объекты, созданные контекстом, автоматически присоединяются к контексту, который их создает. Поскольку объект, который вы получаете, создается MVC, Entity Framework не знает, какие значения были обновлены, а какие нет.

Есть несколько приемов, которые вы можете использовать, чтобы сообщить 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");
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...