【问题标题】:Passing collection data from partial view to controller将集合数据从局部视图传递到控制器
【发布时间】:2017-10-25 08:08:43
【问题描述】:

我需要在从主窗体提交时将动态创建的数据从局部视图传递给控制器​​。

这是返回局部视图的 Action:

[HttpGet]
public virtual PartialViewResult AddItem()
{
    var item = new QuotedItem();
    ViewBag.StockID = new SelectList(db.StockItems.OrderBy(s => s.Name), "StockID", "Name");
    return PartialView("EditorTemplates/QuotedItem", item);
}

这是 QuotedItem 的 EditorTemplate:

@model StockSystem.Models.QuotedItem

<div id="itemRow">

    <span>
        @Html.DropDownListFor(model => model.StockID, null)
        @Html.ValidationMessageFor(model => model.StockID, "", new { @class = "text-danger" })
    </span>
    <span>
        @Html.EditorFor(model => model.Price)
        @Html.ValidationMessageFor(model => model.Price, "", new { @class = "text-danger" })
    </span>
    <span>
        @Html.EditorFor(model => model.Quantity)
        @Html.ValidationMessageFor(model => model.Quantity, "", new { @class = "text-danger" })
    </span>

    <a href="#" class="deleteSmall"></a>

</div>

这是视图:

@model StockSystem.Models.Quote

@{
    ViewBag.Title = "Create";
}

<h2>New Quote for @ViewBag.Customer</h2>

<hr />
@using (Html.BeginForm()) 
{
    @Html.AntiForgeryToken()
    @Html.ValidationSummary(true, "", new { @class = "text-danger" })
    @Html.Hidden("CustomerID", (object)ViewBag.CustomerID)

    <div class="addItem">
        @Ajax.ActionLink(" ", "AddItem",
        new AjaxOptions
        {
            UpdateTargetId = "editorRows",
            InsertionMode = InsertionMode.InsertAfter,
            HttpMethod = "GET"
        })
    </div>

    <div id="editorRows">
        @Html.EditorFor(q => q.QuotedItems)
    </div>

    <p></p>

    <div>
        <input class="add" type="submit" value="" />
        <a class="back" href="@Url.Action("Index", "Quotes", new { id = ViewBag.CustomerID })"></a>
    </div>
}

这里是创建操作:

 public ActionResult Create(int id)
 {
     var customer = db.Customers.Find(id);
     ViewBag.CustomerID = id;
     ViewBag.Customer = customer.CustomerName;
     var quote = new Quote() { QuotedItems = new List<QuotedItem>() };
     return View(quote);
 }

这是 QuotedItem 的 EF 模型:

public partial class QuotedItem
{
    public int QuotedItemID { get; set; }
    public int QuoteID { get; set; }
    public int StockID { get; set; }
    public int Quantity { get; set; }
    public decimal Price { get; set; }

    public virtual Quote Quote { get; set; }
    public virtual StockItem StockItem { get; set; }
}

并引用:

public partial class Quote
{
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
    public Quote()
    {
        this.QuotedItems = new HashSet<QuotedItem>();
    }

    public int QuoteID { get; set; }
    public int CustomerID { get; set; }
    public int UserID { get; set; }
    public System.DateTime QuoteDate { get; set; }
    public string QuoteRef { get; set; }

    public virtual Customer Customer { get; set; }
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<QuotedItem> QuotedItems { get; set; }
    public virtual User User { get; set; }
}

我可以将项目添加到页面,但它们不会添加到提交时的报价中。

 [HttpPost]
 [ValidateAntiForgeryToken]
 public ActionResult Create([Bind(Include = "QuoteID,CustomerID,UserID,QuoteDate,QuoteRef,QuotedItems")] Quote quote) //, List<QuotedItem> items
 {
     if (ModelState.IsValid)
     {
         //quote.QuotedItems is empty, how do I bind this data and save to database?         
         db.Quotes.Add(quote);
         db.SaveChanges();
         return RedirectToAction("Index", new { id = quote.CustomerID });
     }

     return View(quote);
 }

集合未发送到控制器。这是怎么做到的?

谢谢

编辑:我正在考虑尝试这个:

 [HttpPost]
 [ValidateAntiForgeryToken]
 public ActionResult Create([Bind(Include = "QuoteID,CustomerID,UserID,QuoteDate,QuoteRef,QuotedItems")] Quote quote, List<QuotedItem> items)
 {
     if (ModelState.IsValid)
     {
         quote.QuotedItems = items;
         db.Quotes.Add(quote);
         db.SaveChanges();
         return RedirectToAction("Index", new { id = quote.CustomerID });
     }

     return View(quote);
 }

但我认为一定有更好的方法。如果我尝试这种方法,我仍然不完全确定如何将它发送到控制器,我假设它是 Html.BeginForm() 中的一个参数?我对 MVC 还很陌生,但仍在掌握约定。

【问题讨论】:

    标签: entity-framework model-view-controller partial-views icollection


    【解决方案1】:

    通过在方法签名中使用 Bind 属性,您可以防止 QuotedItems 属性被发布到控制器操作。

    public ActionResult Create([Bind(Include = "QuoteID,CustomerID,UserID,QuoteDate,QuoteRef")] Quote quote)
    

    QuotedItems 属性名称添加到包含列表应该可以解决这个问题:

    public ActionResult Create([Bind(Include = "QuoteID,CustomerID,UserID,QuoteDate,QuoteRef,QuotedItems")] Quote quote)
    

    编辑

    没有看到您的 QuotedItem 编辑器模板,很难确定,但听起来您的问题可能是添加到列表中的每个项目都没有在构成该项目的元素上设置唯一的 id。如果没有这个,模型绑定器将难以确定哪个元素属于集合中的哪个对象。

    看看这两篇文章,看看它们是否有帮助:

    http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/

    https://www.mattlunn.me.uk/blog/2014/08/how-to-dynamically-via-ajax-add-new-items-to-a-bound-list-model-in-asp-mvc-net/

    编辑 2

    模板中的每个元素都应该有一个唯一的 ID,索引是一个很好的方法,项目 GUID 也是如此(如果有的话);但只要每个元素 ID 对该项目都是唯一的,它就可以工作。

    @model StockSystem.Models.QuotedItem
    
    <div id="itemRow">
    <span>
        @Html.DropDownListFor(model => model.StockID, null)
        @Html.ValidationMessageFor(model => model.StockID, "", new { @class = "text-danger" })
    </span>
    <span>
        @Html.EditorFor(model => model.Price, new { htmlAttributes = new { id = $"[{YOURINDEX}].Price" } })
        @Html.ValidationMessageFor(model => model.Price, "", new { @class = "text-danger" })
    </span>
    <span>
        @Html.EditorFor(model => model.Quantity, new { htmlAttributes = new { id = $"[{YOURINDEX}].Quantity" } })
        @Html.ValidationMessageFor(model => model.Quantity, "", new { @class = "text-danger" })
    </span>
    
    <a href="#" class="deleteSmall"></a>
    

    在上面的代码中,[YOURINDEX] 值需要为添加到集合中的每个新项目递增。

    如何实现和增加该索引取决于您,但我建议您阅读我之前链接到的两篇文章,以了解为什么这是必要的。

    【讨论】:

    • 我已经试过了。集合最终仍然是空的。
    • 您是否在 HttpGet Create 操作中初始化 QuoteItems 集合?
    • Guy - 我已经编辑了我的问题以显示创建操作。
    • 我还编辑了问题以包含 QuoteQuotedItem 的模型我正在使用实体框架来生成这些。
    • 我已将问题编辑为还包括编辑器模板。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-28
    • 2017-12-16
    • 1970-01-01
    • 2023-03-13
    相关资源
    最近更新 更多