在简短 :我如何成功,而无需包括编辑视图的内部模型中的每个单场编辑DB的条目?
UPDATE
所以我在DB(某条)的项目。 我想编辑的文章。 文章中,我编辑了许多属性(ID,CreatedBy,dateCreated会,标题,正文)。 一些属性不需要更改(如身份证,CreatedBy,dateCreated会)。 所以在我的编辑视图,我只想为可以改变(如标题,正文)字段的输入字段。 当我实现一个编辑视图这样,模型绑定失败。 我没有为提供输入的任何字段被设置为一些“默认”的值(如dateCreated会被设置为01/01/0001 12:00:00 AM)。 如果我对每一个领域做的电源输入,一切工作正常,如预期的那样文章被编辑。 我不知道这是否在说,“模型绑定失败”是正确的必然,这么多说:“该系统填补了用,如果没有输入字段在编辑视图为他们提供不正确的数据字段。”
我怎么能以这样的方式,我只需要提供输入字段,可以/需要编辑,因此,当在控制器上的编辑方法被调用,如dateCreated会字段填充正确,并且没有设置域创建,编辑,查看一些默认情况下,不正确的值? 这里是我的编辑方法,因为它目前为:
[HttpPost]
public ActionResult Edit(Article article)
{
// Get a list of categories for dropdownlist
ViewBag.Categories = GetDropDownList();
if (article.CreatedBy == (string)CurrentSession.SamAccountName || (bool)CurrentSession.IsAdmin)
{
if (ModelState.IsValid)
{
article.LastUpdatedBy = MyHelpers.SessionBag.Current.SamAccountName;
article.LastUpdated = DateTime.Now;
article.Body = Sanitizer.GetSafeHtmlFragment(article.Body);
_db.Entry(article).State = EntityState.Modified;
_db.SaveChanges();
return RedirectToAction("Index", "Home");
}
return View(article);
}
// User not allowed to edit
return RedirectToAction("Index", "Home");
}
而编辑查看是否有帮助:
. . .
@using (Html.BeginForm()) {
@Html.ValidationSummary(true)
<fieldset>
<legend>Article</legend>
<p>
<input type="submit" value="Save" /> | @Html.ActionLink("Back to List", "Index")
</p>
@Html.Action("Details", "Article", new { id = Model.Id })
@Html.HiddenFor(model => model.CreatedBy)
@Html.HiddenFor(model => model.DateCreated)
<div class="editor-field">
<span>
@Html.LabelFor(model => model.Type)
@Html.DropDownListFor(model => model.Type, (SelectList)ViewBag.Categories)
@Html.ValidationMessageFor(model => model.Type)
</span>
<span>
@Html.LabelFor(model => model.Active)
@Html.CheckBoxFor(model => model.Active)
@Html.ValidationMessageFor(model => model.Active)
</span>
<span>
@Html.LabelFor(model => model.Stickied)
@Html.CheckBoxFor(model => model.Stickied)
@Html.ValidationMessageFor(model => model.Stickied)
</span>
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Title)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Title)
@Html.ValidationMessageFor(model => model.Title)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Body)
</div>
<div class="editor-field">
@* We set the id of the TextArea to 'CKeditor' for the CKeditor script to change the TextArea into a WYSIWYG editor. *@
@Html.TextAreaFor(model => model.Body, new { id = "CKeditor", @class = "text-editor" })
@Html.ValidationMessageFor(model => model.Body)
</div>
</fieldset>
. . .
如果我离开了这两个输入:
@Html.HiddenFor(model => model.CreatedBy)
@Html.HiddenFor(model => model.DateCreated)
当编辑方法被调用时,它们设置为默认值。 CreatedBy设置为NULL,创建设置为01/01/0001 12:00:00 AM
他们为什么不设置值,因为它们是在DB当前设置为?
但一些调查研究后,我来到一些工具,帮助视图模型的过程 - 一个是AutoMapper和其他InjectValues。 我InjectValues去,主要是因为它不仅可以“扁平化”的对象(地图对象 - > B),但它也可以“unflatten”他们(地图对象B - > A) - 这AutoMapper遗憾的是缺少外的the-盒 - 这是我需要以更新数据库内的值做。
现在,而不是送我的文章模型以其全部财产对我的看法,我只创建包含下列属性的ArticleViewModel:
public class ArticleViewModel
{
public int Id { get; set; }
[MaxLength(15)]
public string Type { get; set; }
public bool Active { get; set; }
public bool Stickied { get; set; }
[Required]
[MaxLength(200)]
public string Title { get; set; }
[Required]
[AllowHtml]
public string Body { get; set; }
}
当我创建项目,而不是发送文章对象( 每个属性),我送视图中成为“简单”模式-我ArticleViewModel:
//
// GET: /Article/Create
public ActionResult Create()
{
return View(new ArticleViewModel());
}
对于POST方法,我们把我们送到了查看视图模型,并使用其数据来创建一个数据库中的新条款。 我们通过“unflattening”视图模型上一个文章对象做到这一点:
//
// POST: /Article/Create
public ActionResult Create(ArticleViewModel articleViewModel)
{
Article article = new Article(); // Create new Article object
article.InjectFrom(articleViewModel); // unflatten data from ViewModel into article
// Fill in the missing pieces
article.CreatedBy = CurrentSession.SamAccountName; // Get current logged-in user
article.DateCreated = DateTime.Now;
if (ModelState.IsValid)
{
_db.Articles.Add(article);
_db.SaveChanges();
return RedirectToAction("Index", "Home");
}
ViewBag.Categories = GetDropDownList();
return View(articleViewModel);
}
在“缺件”填写的文章属性我不想在视图设置,也不需要在编辑视图进行更新(或全部,对于这个问题)。
编辑方法是几乎一样的,只不过不是发送一个新的视图模型来我们发送一个ViewModel预先填充来自我们的DB数据视图。 我们通过检索数据库的文章和数据压扁到视图模型做到这一点。 首先,GET方法:
//
// GET: /Article/Edit/5
public ActionResult Edit(int id)
{
var article = _db.Articles.Single(r => r.Id == id); // Retrieve the Article to edit
ArticleViewModel viewModel = new ArticleViewModel(); // Create new ArticleViewModel to send to the view
viewModel.InjectFrom(article); // Inject ArticleViewModel with data from DB for the Article to be edited.
return View(viewModel);
}
对于POST方法,我们要采取从查看发送的数据,并更新存储在数据库与它的文章。 要做到这一点,我们简单地逆转“unflattening”视图模型扁平化过程到第对象 - 就像我们做我们的创建方法的POST版本:
//
// POST: /Article/Edit/5
[HttpPost]
public ActionResult Edit(ArticleViewModel viewModel)
{
var article = _db.Articles.Single(r => r.Id == viewModel.Id); // Grab the Article from the DB to update
article.InjectFrom(viewModel); // Inject updated values from the viewModel into the Article stored in the DB
// Fill in missing pieces
article.LastUpdatedBy = MyHelpers.SessionBag.Current.SamAccountName;
article.LastUpdated = DateTime.Now;
if (ModelState.IsValid)
{
_db.Entry(article).State = EntityState.Modified;
_db.SaveChanges();
return RedirectToAction("Index", "Home");
}
return View(viewModel); // Something went wrong
}
我们还需要改变强类型的创建和编辑的意见,以期待一个ArticleViewModel而不是一篇文章:
@model ProjectName.ViewModels.ArticleViewModel
就是这样!
因此,在总结,你可以实现的ViewModels只是你的模型作品传递给你的意见。 然后,您可以只更新这些作品,通过视图模型回控制器,并使用更新的信息视图模型更新的实际模型。
视图模型例如:
public class ArticleViewModel {
[Required]
public string Title { get; set; }
public string Content { get; set; }
}
例如绑定
public ActionResult Edit(int id, ArticleViewModel article) {
var existingArticle = db.Articles.Where(a => a.Id == id).First();
existingArticle.Title = article.Title;
existingArticle.Content = article.Content;
db.SaveChanges();
}
这是简单的例子,但你应该看看的ModelState检查,如果模型没有错误,请检查授权和移动这个代码从控制器到服务类的,但那是另一个教训。
这是正确的编辑方法:
[HttpPost]
public ActionResult Edit(Article article)
{
// Get a list of categories for dropdownlist
ViewBag.Categories = GetDropDownList();
if (article.CreatedBy == (string)CurrentSession.SamAccountName || (bool)CurrentSession.IsAdmin)
{
if (ModelState.IsValid)
{
var existingArticle = _db.Articles.First(a => a.Id = article.Id);
existingArticle.LastUpdatedBy = MyHelpers.SessionBag.Current.SamAccountName;
existingArticle.LastUpdated = DateTime.Now;
existingArticle.Body = Sanitizer.GetSafeHtmlFragment(article.Body);
existingArticle.Stickied = article.Stickied;
_db.SaveChanges();
return RedirectToAction("Index", "Home");
}
return View(article);
}
// User not allowed to edit
return RedirectToAction("Index", "Home");
}
没有视图模型的另一个好方法
// POST: /Article/Edit/5
[HttpPost]
public ActionResult Edit(Article article0)
{
var article = _db.Articles.Single(r => r.Id == viewModel.Id); // Grab the Article from the DB to update
article.Stickied = article0.Stickied;
// Fill in missing pieces
article.LastUpdatedBy = MyHelpers.SessionBag.Current.SamAccountName;
article.LastUpdated = DateTime.Now;
if (ModelState.IsValid)
{
_db.Entry(article0).State = EntityState.Unchanged;
_db.Entry(article).State = EntityState.Modified;
_db.SaveChanges();
return RedirectToAction("Index", "Home");
}
return View(article0); // Something went wrong
}
使用的ViewModels。
通过我继续寻找解决这个问题的研究,我认为,使用这些东西叫做“的ViewModels”是要走的路。 如在解释后吉米·博加德,是的ViewModels办法“从一个单一的实体展示的信息片。”
asp.net-MVC-视图模型图案让我为首的正确的轨道上; 我还检查了一些作者发表,以进一步掌握视图模型概念(博客文章由吉米就是其中之一)的外部资源。
除了回答,AutoMapper也可以用来unflatten它。 使用AutoMapper到unflatten一个DTO