将 jQuery 数据从 View 传递到 Controller 并将其保存为多对多

Pass jQuery data from View to Controller and save it as many-to-many

我有一个多对多的关系。我从 asp.net 3.0 和 ef core 3.1

中的脚手架为以下 2 个实体(产品和发票)生成了控制器和视图

我可以从两个实体进行 CRUD。

在发票视图页面中,我需要有一个从产品 table 提供的下拉列表,并将 ItemName 添加到下拉列表中。 我已经通过 ViewData["Products"] 做到了,它工作正常。

当用户从那个下拉列表中选择时,旁边有一个 'Add item' 按钮, 如果用户单击“添加项目”按钮,则必须在页面下方添加项目名称。我已经通过 jquery 及其作品

做到了

页面底部有一个保存按钮,点击后,它只会通过绑定将发票模型传递给控制器​​(这是正确的行为), 但我不确定如何将所有添加的项目(仅它们的 ID)传递给控制器​​以保存在 join-table (ProductInvoice).

不确定,也许我没有正确设计应用程序的体系结构,这就是为什么我写了整个 scenario/use-case 也许你可以建议我重新设计。

简而言之,用例是:用户必须将 itemName(从产品 table 中获取)添加到发票并将其保存为多对多关系。

**如何保存我在发票页面上添加的所有 ItemId,将它们保存到 ProductInvoice table 作为多对多,

如何将它们从视图传递给控制器​​?**

我搜索了一整天,我找不到怎么做,这就是我 post.

的原因
public class Product
{
    public int ProductId { get; set; }
    public int Price { get; set; }
    public string ItemName { get; set; }    
    public IList<ProductInvoice> ProductInvoices { get; set; }
}

public class Invoice
{
    public int InvoiceId { get; set; }
    public DateTime InvoiceDate { get; set; }
    public IList<ProductInvoice> ProductInvoices { get; set; }
}
    
public class ProductInvoice
{
    [Key]
    public int ProductId { get; set; }
    public Product Product { get; set; }

    [Key]
    public int InvoiceId { get; set; }
    public Invoice Invoice { get; set; }
}

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("InvoiceId,InvoiceDate")] Invoice invoice)
{
    if (ModelState.IsValid)
    {
        _context.Add(invoice);
        await _context.SaveChangesAsync();
        return RedirectToAction(nameof(Index));
    }
    return View(invoice);
}


<script>
        $(document).ready(function () {

            var totalInvoice = 0;

            $("#btn-add-item").click(function () {

                var selectedItem = $('#SelectedProducts :selected').text();
                var getCostPerItem = $('#SelectedProducts :selected').val();

                getCostPerItem = getCostPerItem.split("-")[1];
                getCostPerItem = getCostPerItem.split(".")[0];
                totalInvoice = parseInt(totalInvoice) + parseInt(getCostPerItem);

                $('<div id="created_div">' + '<b>+</b> ' + selectedItem + ' :  $ ' + ' ' + getCostPerItem + '<a href="#" class="btn btn-danger btn-sm btn-remove-item float-right">Remove</a></div><br>').insertAfter('#main-body-card');
                $("#total-invoice-input").val(totalInvoice);
            });
        });
    </script>

这是您可以遵循的完整工作演示:

型号:

public class Product
{
    public int ProductId { get; set; }
    public int Price { get; set; }
    public string ItemName { get; set; }
    public IList<ProductInvoice> ProductInvoices { get; set; }
}

public class Invoice
{
    public int InvoiceId { get; set; }
    public DateTime InvoiceDate { get; set; }
    public IList<ProductInvoice> ProductInvoices { get; set; }
}

public class ProductInvoice
{
    [Key]
    public int ProductId { get; set; }
    public Product Product { get; set; }

    [Key]
    public int InvoiceId { get; set; }
    public Invoice Invoice { get; set; }
}

查看:

首先,在我的项目中,产品下拉列表值为 ProductId,文本为 ItemName

然后,要传递相关的 ProductId 并添加到 Invoice 模型,您需要添加隐藏(或不隐藏)输入,名称如下:ProductInvoices[index].ProductId.

最后,绑定属性([Bind("InvoiceId,CreatedDate,CreateByUser,TotalInvoice")])中的参数必须匹配模型Invoice

@model Invoice    
<div class="row">
    <div class="col-md-4">
        <form asp-action="Create">
            <div id="main-body-card"></div>
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="InvoiceDate" class="control-label"></label>
                <input asp-for="InvoiceDate" class="form-control" />
                <span asp-validation-for="InvoiceDate" class="text-danger"></span>
            </div>
            <div class="form-group">
                <select id="SelectedProducts"  asp-items="(SelectList)@ViewData["Products"]"></select>
                <button type="button" id="btn-add-item">Add</button>
            </div>
            <label>total: </label><input id="total-invoice-input" />
            <div class="form-group">
                <input type="submit" value="Create" class="btn btn-primary" />
            </div>
        </form>
    </div>
</div>      
@section Scripts
{
    <script>
        $(document).ready(function () {
            var totalInvoice = 0;
            var i = 0;      //add this...
            $("#btn-add-item").click(function () {    
                var selectedItem = $('#SelectedProducts :selected').text();
                var getCostPerItem = $('#SelectedProducts :selected').val();            
                totalInvoice = parseInt(totalInvoice) + parseInt(getCostPerItem);   
                $('<div id="created_div">' + '<b>+</b> ' + selectedItem + ' :  $ ' + ' ' + getCostPerItem + '<a href="#" class="btn btn-danger btn-sm btn-remove-item float-right">Remove</a></div><br>').insertAfter('#main-body-card');
                //add this....
                $("<input value='"+getCostPerItem+"' name='ProductInvoices[" + i + "].ProductId' hidden/>").insertAfter('#created_div');
                $("#total-invoice-input").val(totalInvoice);
                i++;   //add this...
            });
        });
    </script>
}

控制器:

public IActionResult Create()
{
    ViewData["Products"] = new SelectList(_context.Product.ToList(), "ProductId", "ItemName");
    return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("InvoiceId,InvoiceDate,ProductInvoices")] Invoice invoice)
{
    if (ModelState.IsValid)
    {
        _context.Add(invoice);
        await _context.SaveChangesAsync();
        return RedirectToAction(nameof(Index));
    }
    return View(invoice);
}

结果: