Cal*_*man 10 asp.net-mvc model-binding viewmodel valueinjecter
简而言之:如何成功编辑数据库条目而无需在编辑视图中包含模型的每个字段?
更新
所以我在DB(文章)中有一个项目.我想编辑一篇文章.我编辑的文章有很多属性(Id,CreatedBy,DateCreated,Title,Body).其中一些属性永远不需要更改(如Id,CreatedBy,DateCreated).因此,在我的编辑视图中,我只想要可以更改的字段的输入字段(如标题,正文).当我像这样实现编辑视图时,模型绑定失败.我没有提供输入的任何字段都设置为某个"默认"值(如DateCreated设置为01/01/0001 12:00:00 am).如果我确实为每个字段提供输入,一切正常,文章按预期编辑.我不知道是否正确地说"模型绑定失败"是必要的,如果"如果在编辑视图中没有为它们提供输入字段,则系统会填充包含不正确数据的字段".
如何以这样的方式创建编辑视图:我只需要为可以/需要编辑的字段提供输入字段,以便在调用Controller中的Edit方法时,正确填充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");
}
Run Code Online (Sandbox Code Playgroud)
编辑视图是否有帮助:
. . .
@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>
. . .
Run Code Online (Sandbox Code Playgroud)
如果我遗漏这两个输入:
@Html.HiddenFor(model => model.CreatedBy)
@Html.HiddenFor(model => model.DateCreated)
Run Code Online (Sandbox Code Playgroud)
调用Edit方法时,它们将设置为默认值.CreatedBy设置为Null,Created设置为01/01/0001 12:00:00 am
为什么它们没有设置为数据库中当前设置的值?
Cal*_*man 10
经过一些研究后,我发现了一些辅助ViewModel过程的工具 - 一个是AutoMapper和其他InjectValues.我选择InjectValues主要是因为它不仅可以"展平"对象(地图对象a - > b),而且它还可以"展开"它们(地图对象b - > a) - 不幸的是,AutoMapper缺乏这样的东西.框 - 我需要做的事情才能更新数据库中的值.
现在,我创建了一个仅包含以下属性的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; }
}
Run Code Online (Sandbox Code Playgroud)
当我创建文章时,不是发送文章对象(包含每个属性),而是发送查看'更简单'的模型 - 我的ArticleViewModel:
//
// GET: /Article/Create
public ActionResult Create()
{
return View(new ArticleViewModel());
}
Run Code Online (Sandbox Code Playgroud)
对于POST方法,我们将ViewModel发送到View并使用其数据在DB中创建新文章.我们通过将ViewModel"unflattening"到Article对象来实现:
//
// 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);
}
Run Code Online (Sandbox Code Playgroud)
填写的"缺失的部分"是我不想在视图中设置的文章属性,也不需要在编辑视图中更新(或者根本不需要更新).
Edit方法几乎相同,除了不向View发送新的ViewModel,我们发送一个预先填充了来自数据库的数据的ViewModel.我们通过从DB检索文章并将数据展平到ViewModel来完成此操作.首先,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);
}
Run Code Online (Sandbox Code Playgroud)
对于POST方法,我们希望获取从View发送的数据并使用它更新存储在DB中的文章.要做到这一点,我们只需将ViewModel"unflattening"到Article对象上即可反转展平过程 - 就像我们对Create方法的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
}
Run Code Online (Sandbox Code Playgroud)
我们还需要更改强类型的"创建和编辑"视图以期望ArticleViewModel而不是文章:
@model ProjectName.ViewModels.ArticleViewModel
Run Code Online (Sandbox Code Playgroud)
就是这样!
总而言之,您可以实现ViewModels,只将模型的各个部分传递给您的视图.然后,您可以只更新这些部分,将ViewModel传递回Controller,并使用ViewModel中的更新信息来更新实际模型.
| 归档时间: |
|
| 查看次数: |
11347 次 |
| 最近记录: |