Успешное редактирование модели без множества скрытых полей

In Short: Как мне успешно отредактировать запись в БД без необходимости включать каждое отдельное поле для модели в окне редактирования?

UPDATE
Итак, у меня есть пункт в БД (статья). Я хочу редактировать статью. Статья, которую я редактирую, имеет много свойств (Id, CreatedBy, DateCreated, Title, Body). Некоторые из этих свойств никогда не нужно изменять (например, Id, CreatedBy, DateCreated). Поэтому в моем редактируемом представлении я хочу только поля ввода для полей, которые можно изменить (например, заголовок, текст). Когда я реализую вид редактирования таким образом, привязка модели завершается неудачно. Любые поля, для которых я не предоставил входные данные, устанавливаются на некоторые значения по умолчанию. значение (например, DateCreated устанавливается 01/01/0001 12:00:00 утра). Если яdo Введите входные данные для каждого поля, все работает нормально и статья отредактирована, как и ожидалось Я не знаю, правильно ли говорить, что «Привязка модели не удалась». обязательно, так что "система заполняет поля неверными данными, если для них не было введено поле ввода в представлении редактирования".

Как я могу создать представление редактирования таким образом, что мне нужно только указать поля ввода для полей, которые могут / нуждаются в редактировании, чтобы при вызове метода редактирования в контроллере поля, такие как DateCreated, заполнялись правильно, а не устанавливались по умолчанию, неправильное значение? Вот мой метод Edit в его нынешнем виде:

    [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");   
    }

И Edit View, если это поможет:

. . .
@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)

когда вызывается метод Edit, они устанавливаются в значения по умолчанию. CreatedBy установлен вNullСоздано установлено в01/01/0001 12:00:00am

Почему они не установлены в значения, как они в настоящее время установлены в БД?

Ответы на вопрос(5)

В дополнение к ответу AutoMapper также может быть использован для его разматывания. Использование AutoMapper для раскрепощения DTO

еще один хороший способ без модели представления

// 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
}
Решение Вопроса

После еще одного исследования я наткнулся на некоторые инструменты, которые помогают в процессе ViewModel - одним из них является AutoMapper & amp; другие InjectValues. Я пошел с InjectValues прежде всего потому, что он может не только «сгладить» объекты (объект карты a -> b), но он также может «открывать» их (объект карты b -> a) - то, чего, к сожалению, в AutoMapper нет в готовом виде, - то, что мне нужно сделать, чтобы обновить значения внутри БД.

Теперь вместо того, чтобы отправлять мою модель Article со всеми ее свойствами в мои представления, я создал 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; }
}

Когда я создаю статью, вместо отправки объекта статьи (сevery свойство) Я отправляю просмотр "проще" модель - моя ArticleViewModel:

//
// GET: /Article/Create

public ActionResult Create()
{
    return View(new ArticleViewModel());
}

Для метода POST мы берем ViewModel, который мы отправили в View, и используем его данные для создания новой статьи в БД. Мы делаем это с помощью функции «открепление» ViewModel на объект 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);            
}

"Пропавшие кусочки" заполнены те свойства статьи, которые я не хотел устанавливать в представлении, и их не нужно обновлять в представлении «Правка» (или вообще, в этом отношении).

Метод Edit почти такой же, за исключением того, что вместо отправки новой ViewModel в View мы отправляем ViewModel, предварительно заполненную данными из нашей БД. Мы делаем это путем извлечения статьи из БД и сглаживания данных на 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);
    }

Для метода POST мы хотим взять данные, отправленные из View, и обновить им статью, хранящуюся в БД. Чтобы сделать это, мы просто обращаемс к процессу сглаживани путем "безразличени". ViewModel на объект Article - так же, как мы делали для POST-версии нашего метода Create:

    //
    // 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
    }

Нам также нужно изменить строго типизированный Create & amp; Отредактируйте представления так, чтобы они ожидали ArticleViewModel вместо Article:

@model ProjectName.ViewModels.ArticleViewModel

И это все!

Итак, в итоге, вы можете реализовать ViewModels, чтобы передать толькоpieces ваших моделей для ваших просмотров. Затем вы можете обновить только эти части, передать ViewModel обратно в контроллер и использовать обновленную информацию в ViewModel для обновленияactual Модель.

использованиеViewModels.

Благодаря моему постоянному исследованию в поиске решения этой проблемы я считаю, что с помощью этих вещей, называемых «ViewModels» это путь Как объяснено всообщение Джимми Богард, ViewModels - это способ «показать фрагмент информации из одного объекта».

asp.net-MVC-View-модель-модель вывел меня на правильный путь; Я все еще проверяю некоторые из внешних ресурсов, которые автор опубликовал, чтобы лучше понять концепцию ViewModel (одним из них является пост в блоге Джимми).

Посмотреть пример модели:

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, чтобы проверить, нет ли в модели ошибок, проверить авторизацию и переместить этот код из контроллера в классы обслуживания, но это еще один урок.

This is corrected Edit method:

[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");   
}

Ваш ответ на вопрос