In Short: How do I successfully edit a DB entry without needing to include every single field for the Model inside of the Edit View?
UPDATE
So I have an item in the DB (an Article). I want to edit an article. The article I edit has many properties (Id, CreatedBy, DateCreated, Title, Body). Some of these properties never need to change (like Id, CreatedBy, DateCreated). So in my Edit View, I only want input fields for fields that can be changed (like Title, Body). When I implement an Edit View like this, Model Binding fails. Any fields that I didn't supply an input for gets set to some 'default' value (like DateCreated gets set to 01/01/0001 12:00:00am). If I do supply inputs for every field, everything works fine and the article is edited as expected. I don't know if it's correct in saying that "Model Binding fails" necessarily, so much as that "the system fills in fields with incorrect data if no Input field was supplied for them in the Edit View."
How can I create an Edit View in such a way that I only need to supply input fields for fields that can/need editing, so that when the Edit method in the Controller is called, fields such as DateCreated are populated correctly, and not set to some default, incorrect value? Here is my Edit method as it currently stands:
[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");
}
And the Edit View if it helps:
. . .
@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>
. . .
If I were to leave out these two inputs:
@Html.HiddenFor(model => model.CreatedBy)
@Html.HiddenFor(model => model.DateCreated)
when the Edit method is called, they're set to default values. CreatedBy is set to Null, Created is set to 01/01/0001 12:00:00am
Why are they not set to the values as they are currently set to in the DB?
See Question&Answers more detail:os