成功的模型编辑没有一堆隐藏字段 [英] Successful Model Editing without a bunch of hidden fields

查看:149
本文介绍了成功的模型编辑没有一堆隐藏字段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在短:我如何成功地编辑数据库条目,而不需要包括每一个字段编辑视图内的模型

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?

更新结果
所以,我在DB(文章)的项目。我想编辑的文章。文章中,我的编辑有许多属性(ID,CreatedBy,dateCreated会,标题,正文)。其中一些属性不需要更改(如身份证,CreatedBy,dateCreated会)。所以在我的编辑视图,我只想为可以改变(如标题,正文)字段输入字段。当我实现一个编辑视图这个样子,模型绑定失败。我没有为提供输入的任何字段被设置为某些默认值(如dateCreated会被设置为01/01/0001 12:00:00 AM)。如果我的的每个字段电源输入,一切工作正常,如预期的那样文章被编辑。我不知道这是否在说,模型绑定失败是正确的必然,这么多的系统与如果没有输入字段在编辑视图为他们提供不正确的数据字段填写。

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."

我怎么能以这样的方式,我只需要提供输入域,可以/需要编辑,这样当控制器编辑方法被调用,如dateCreated会字段正确填充字段创建,编辑,查看,而不是设置一些默认的,不正确的值?这里是我的编辑方法,因为它目前为:

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)

当编辑方法被调用时,它们设置为默认值。 CreatedBy设置为的,创建设置为 01/01/0001 12:00:00 AM

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

他们为什么不设置这些值,因为它们在DB当前设置为?

Why are they not set to the values as they are currently set to in the DB?

推荐答案

但一些更多的研究,我来到一些工具,协助视图模型的过程后 - 一个是AutoMapper&安培;其他InjectValues​​。我InjectValues​​去,主要是因为它不仅可以扁平化的对象(地图对象 - > B),但它也可以unflatten他们(地图对象B - > A) - 这AutoMapper遗憾的是缺少外的任何─盒 - 这是我需要,以更新数据库内的值做

After yet some more research I came upon some tools that assist in the ViewModel process - one being AutoMapper & the other InjectValues. I went with InjectValues primarily because it can not only "flatten" objects (map object a -> b) but it can also "unflatten" them (map object b -> a) - something that AutoMapper unfortunately lacks out-of-the-box - something I need to do in order to update values inside of a DB.

现在,而不是发送我的文章模型以其全部财产对我的看法,我创建一个只包含以下属性的ArticleViewModel:

Now, instead of sending my Article model with all of its properties to my views, I created an ArticleViewModel containing only the following properties:

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:

When I Create an Article, instead of sending an Article object (with every property) I send the View a 'simpler' model - my ArticleViewModel:

//
// GET: /Article/Create

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

有关POST方法我们采取的视图模型我们送到查看和使用它的数据创建一个数据库中的新条款。我们通过unflattening视图模型上的一篇文章对象:

For the POST method we take the ViewModel we sent to the View and use its data to Create a new Article in the DB. We do this by "unflattening" the ViewModel onto an Article object:

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

在缺件填写的项目属性我不想在视图设置,也不需要在编辑视图进行更新(或全部,对于这个问题)。

The "missing pieces" filled in are Article properties I didn't want to set in the View, nor do they need to be updated in the Edit view (or at all, for that matter).

编辑方法是pretty大致相同,除了没有发送一个新的视图模型来查看我们发送一个ViewModel pre填充来自我们的DB数据。我们通过检索数据库的文章和数据压扁到视图模型做到这一点。首先,GET方法:

The Edit method is pretty much the same, except instead of sending a fresh ViewModel to the View we send a ViewModel pre-populated with data from our DB. We do this by retrieving the Article from the DB and flattening the data onto the ViewModel. First, the GET method:

    //
    // 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版本我们创建的方法:

For the POST method we want to take the data sent from the View and update the Article stored in the DB with it. To do this we simply reverse the flattening process by 'unflattening' the ViewModel onto the Article object - just like we did for the POST version of our Create method:

    //
    // 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,而不是一篇文章:

We also need to change the strongly-typed Create & Edit views to expect an ArticleViewModel instead of an Article:

@model ProjectName.ViewModels.ArticleViewModel

这就是它!

因此​​,在总结,就可以实现的ViewModels刚刚的您的模型作品的传递到你的观点。然后,您可以只更新这些作品,通过视图模型回控制器,并使用更新后的信息视图模型更新的实际的模型。

So in summary, you can implement ViewModels to pass just pieces of your Models to your Views. You can then update just those pieces, pass the ViewModel back to the Controller, and use the updated information in the ViewModel to update the actual Model.

这篇关于成功的模型编辑没有一堆隐藏字段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆