成功的模型编辑没有一大堆隐藏字段(Successful Model Editing without

2019-06-25 07:15发布

在简短 :我如何成功,而无需包括编辑视图的内部模型中的每个单场编辑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当前设置为?

Answer 1:

但一些调查研究后,我来到一些工具,帮助视图模型的过程 - 一个是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只是你的模型作品传递给你的意见。 然后,您可以只更新这些作品,通过视图模型回控制器,并使用更新的信息视图模型更新的实际模型。



Answer 2:

视图模型例如:

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


Answer 3:

没有视图模型的另一个好方法

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


Answer 4:

使用的ViewModels。

通过我继续寻找解决这个问题的研究,我认为,使用这些东西叫做“的ViewModels”是要走的路。 如在解释后吉米·博加德,是的ViewModels办法“从一个单一的实体展示的信息片。”

asp.net-MVC-视图模型图案让我为首的正确的轨道上; 我还检查了一些作者发表,以进一步掌握视图模型概念(博客文章由吉米就是其中之一)的外部资源。



Answer 5:

除了回答,AutoMapper也可以用来unflatten它。 使用AutoMapper到unflatten一个DTO



文章来源: Successful Model Editing without a bunch of hidden fields