使用 C# 在 ASP.NET MVC 的同一视图中创建父项和多个子项

Create Parent and Multiple Children in same view in ASP.NET MVC with C#

我一直在网上搜索,试图找到一个简单的解决方案(或至少定期浏览)我认为是常见的 activity,但我一直找不到任何解决方案。我有以下 类:

public class Attribute
{
    ...
    public int Id { get; set; }
    [Required]
    public string AttributeName { get; set; }
    public string Description { get; set; }
    public bool UserCanChangeValue { get; set; }
    public ICollection<AttributeValue> Values { get; set; }
}

class AttributeValue
{
    public int Id { get; set; }
    [ForeignKey("AssociatedAttribute")]
    public int AssociatedAttributeId { get; set; }
    public virtual Attribute AssociatedAttribute { get; set; }
    [Required]
    public string Value { get; set; }
    public bool PromptChange { get; set; } = true;
    public bool ShowonInvoice { get; set; } = false;
}

然后在标准控制器中:

...
// GET: AttributesController/Create
public ActionResult Create()
{
    return View();
}

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Id,Name,Description,Values")] Attribute newAttribute)
....

我感到困惑的是如何在属性必须具有需要同时创建的 1 个或多个值的情况下创建它,并且动态属性可以具有可变编号。理想情况下,我会为要创建的每个属性值在表单中添加行。

一些脚手架细节:

...
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
    <label asp-for="AttributeName" class="control-label"></label>
    <input asp-for="AttributeName" class="form-control" />
    <span asp-validation-for="AttributeName" class="text-danger"></span>
</div>
<div class="form-group">
    <label asp-for="Description" class="control-label"></label>
    <input asp-for="Description" class="form-control" />
    <span asp-validation-for="AttributeName" class="text-danger"></span>
</div>
<div class="form-group form-check">
    <label class="form-check-label">
    <input class="form-check-input" asp-for="UserCanChangeValue" /> @Html.DisplayNameFor(model => model.UserCanChangeValue)
    </label>
</div>
<div>
    <table>
        <thead>
            <tr>
                <th>Value</th>
                <th>Prompt Change</th>
                <th>Show on Invoice</th>
            </tr>
        </thead>
        <tbody>
            INSERT DYNAMIC NEW VALUE FORM?
        </tbody>
    </table>
</div>

首先,您设置PromptChangeShowonInvoice默认值,如果您不选中checkbox/radio输入,它们将通过默认值(PromptChange= trueShowonInvoice=false) 到后端。但实际上,我更喜欢不设置默认值,可以通过选中或不选中来控制true/false。不知道自己想要哪种方式,自己修改。

那么你的 class AttributeValue 需要 public 访问修饰符。

这是一个您可以遵循的简单工作演示:

型号:

namespace MvcProj5_0.Models
{
    public class Attribute
    {
        public int Id { get; set; }
        [Required]
        public string AttributeName { get; set; }
        public string Description { get; set; }
        public bool UserCanChangeValue { get; set; }
        public ICollection<AttributeValue> Values { get; set; }
    }

    public class AttributeValue
    {
        public int Id { get; set; }     //add a primary key
        [ForeignKey("AssociatedAttribute")]
        public int AssociatedAttributeId { get; set; }
        public virtual Attribute AssociatedAttribute { get; set; }
        [Required]
        public string Value { get; set; }
        public bool PromptChange { get; set; } 
        public bool ShowonInvoice { get; set; } 
    }
}

视图(Create.cshtml):

@model MvcProj5_0.Models.Attribute    
<form asp-action="Create">
    <div asp-validation-summary="ModelOnly" class="text-danger"></div>
    <div class="form-group">
        <label asp-for="AttributeName" class="control-label"></label>
        <input asp-for="AttributeName" class="form-control" />
        <span asp-validation-for="AttributeName" class="text-danger"></span>
    </div>
    <div class="form-group">
        <label asp-for="Description" class="control-label"></label>
        <input asp-for="Description" class="form-control" />
        <span asp-validation-for="AttributeName" class="text-danger"></span>
    </div>
    <div class="form-group form-check">
        <label class="form-check-label">
        <input class="form-check-input" asp-for="UserCanChangeValue" /> @Html.DisplayNameFor(model => model.UserCanChangeValue)
        </label>
    </div>
    <button type="button" onclick="AddRow()">Add row</button>    //add button
    <div>
        <table>
            <thead>
                <tr>
                    <th>Value</th>
                    <th>Prompt Change</th>
                    <th>Show on Invoice</th>
                </tr>
            </thead>
            <tbody id="AttributeValueList" data-count="0">         //add id  and data-count
                INSERT DYNAMIC NEW VALUE FORM?
            </tbody>
        </table>
    </div>
    <div class="form-group">
            <input type="submit" value="Create" class="btn btn-primary" />
    </div>
</form> 

Create.cshtml 中的 JS:

@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
    <script>
        function AddRow()
        {
            var countVal = parseInt($('#AttributeValueList').attr('data-count'));    
            var html = '';
            html += '<tr>';
            html += '<td><input type="text" name="Values[' + countVal + '].Value" class="form-control"/></td>';
            html += '<td><input type="checkbox" name="Values[' + countVal + '].PromptChange" value="true"/></td>';
            html += '<td><input type="checkbox" name="Values[' + countVal + '].ShowonInvoice" value="true"/></td>';
            html += '</tr>';
 
            $('#AttributeValueList').append(html);    
            countVal += 1;
            $('#AttributeValueList').attr('data-count', countVal);
        }
    </script>
}

控制器:

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(
     [Bind("Id,AttributeName,Description,UserCanChangeValue,Values")] MvcProj5_0.Models.Attribute attribute)
{
    if (ModelState.IsValid)
    {
        _context.Add(attribute);
        await _context.SaveChangesAsync();
        return RedirectToAction(nameof(Index));
    }
    return View(attribute);
}