在 MVC 中仅更新对象的某些字段的最佳方法是啥?

Posted

技术标签:

【中文标题】在 MVC 中仅更新对象的某些字段的最佳方法是啥?【英文标题】:What is the best way to update only some fields of an object in MVC?在 MVC 中仅更新对象的某些字段的最佳方法是什么? 【发布时间】:2015-09-01 03:14:19 【问题描述】:

我正在尝试更新新闻帖子。该帖子有一个名为 Created 的日期字段,该字段在最初创建记录时填充。我在更新的时候没有包含这个,所以当使用下面的方法时,这个为空并且会抛出一个错误。

我正在使用 MVC 5 和实体框架 6

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "Id,Title,Summary,Content")] Post post) 
    if (ModelState.IsValid) 
        db.Entry(post).State = EntityState.Modified;
        db.SaveChanges();

        return RedirectToAction("Index");
    
    return View(post);

此方法确实有效,但似乎有点笨拙。

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "Id,Title,Summary,Content")] Post post) 
    if (ModelState.IsValid) 
        var newsPost = db.Posts.Find(post.Id);
        if (newsPost == null)  return new HttpStatusCodeResult(HttpStatusCode.BadRequest); 
        newsPost.Title = post.Title;
        newsPost.Summary = post.Summary;
        newsPost.Content = post.Content;
        db.Entry(newsPost).State = EntityState.Modified;
        db.SaveChanges();

        return RedirectToAction("Index");
    
    return View(post);

这样做的最佳实践方法是什么?

谢谢!

【问题讨论】:

我相信使用像 AutoMapper 这样的东西可能是一种方法。 使用 EF6,您应该能够在保存之前使用db.Entry(post).State = EntityState.Modified;,后跟db.Entry(post).Property(x => x.Created).IsModified = false; 我会看看 ViewModel 模式 (geekswithblogs.net/michelotti/archive/2009/10/25/…)。编写视图模型,将其发送到您的 HttpGet 方法,发回 HttpPost 方法,验证,更新您的实体模型。正如 Kamo 所指出的,Automapper 非常适合这一点。然后你可以在你不想更新的字段上使用 html.HiddenFor。 @SteveGreene,感谢您的评论。对于我不想修改的字段,我想避免使用 Html.HiddenFor,因为通过代理或浏览器插件等更改这些字段是微不足道的。 View Models 解决这个问题,这样你就不必传递隐藏字段了。 【参考方案1】:

EF 还有一个简单的内置“AutoMapper”,可以处理标量值。

public class PostViewModel()

     public string Id get;set;
     public string Title get;set;
     public string Summary get;set;
     public string Content get;set;


public ActionResult Edit(PostViewModel viewModel)

    if (ModelState.IsValid) 
        var newsPost = db.Posts.Find(post.Id);
        ...
        db.Entry(newsPost).CurrentValues.SetValues(viewModel);
        ...
    

【讨论】:

这真的是唯一的方法吗...对数据库的额外调用让我畏缩... 但是,这很简单。太好了。【参考方案2】:

我使用存储库方法。效果很好。 它复制不同的列。针对 PUT 的 PATCH 排序

public void CopyUpdate<T> (T modelorig, T model) where T : class
    
        _context.Entry(model).CurrentValues.SetValues(modelorig);

        _context.Set<T>().Add(model);
        _context.Entry(model).State = EntityState.Modified;
        _context.SaveChanges();
    

【讨论】:

【参考方案3】:

假设你想坚持休息,这样做的“正确”方法。是用HttpPatch

https://docs.microsoft.com/en-us/aspnet/core/web-api/jsonpatch?view=aspnetcore-6.0

[HttpPatch]
[ValidateAntiForgeryToken]
public async Task<ActionResult> PatchAsync([FromBody] JsonPatchDocument<Post> patchDoc, int id) 
    
    var post = db.Find(id);
    patchDoc.ApplyTo(post, ModelState);

    if (!ModelState.IsValid)
    
        return BadRequest(ModelState);
    

    await db.SaveChangesAsync();

    return new ObjectResult(post);

【讨论】:

以上是关于在 MVC 中仅更新对象的某些字段的最佳方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

处理不同文化的验证的最佳方法是啥

asp.net mvc - 控制器共享对象的最佳方式是啥

如何在 Entity Framework 6.1 中仅加载子对象的某些字段?

如何在 Java 中仅更新 @Transactional 方法中更改的字段?

在 Spring MVC 中获取当前 URL 的最佳方法是啥?

在 MVC 中,与多个 HTML Helpers 共享 Layout 对象的最佳方式是啥