首页 > 解决方案 > 在 ASP.NET Core Razor 页面的集合中保存项目

问题描述

我不明白如何正确绑定集合中的单个项目。在我的项目中,学生可以使用以下模型制定多个计划:

public class Student
{
    public Student()
    {
        Plans = new HashSet<Plan>();
    }

    public int StudentId { get; set; }
    public string Designee { get; set; }
    public string DesigneePhone { get; set; }

    public virtual ICollection<Plan> Plans { get; set; }
}

public partial class Plan
{
    public int PlanId { get; set; }

    public int StudentId { get; set; }

    public DateTime? StartDate { get; set; }
    public DateTime? EndDate { get; set; }

    public virtual Student Student { get; set; }
}

我在页面上列出了每个计划都有自己的保存按钮。根据这篇 Learn Razor Pages 帖子,我认为我正确使用了 asp-for 助手。

@page "{studentId:int}"
@model CollectionTest.PlansModel

<form asp-page-handler="SaveMain" method="post">
    <div class="row mt-3">
        <input type="hidden" asp-for="Student.StudentId" />
        <div class="col">
            <label asp-for="Student.Designee"></label>
            <input asp-for="Student.Designee" class="form-control" />
        </div>
        <div class="col">
            <label asp-for="Student.DesigneePhone"></label>
            <input asp-for="Student.DesigneePhone" class="form-control" />
        </div>
        <div class="col-auto align-self-end">
            <input type="submit" value="Save" class="btn btn-primary" />
        </div>
    </div>
</form>

<hr />

@for (int i = 0; i < Model.Student.Plans.Count(); i++)
{
    var planId = Model.Student.Plans.ToList()[i].PlanId.ToString();

    <div id="@("card_Plan" + planId)" class="card">
        <div class="card-header">
            <h5>Plan #@planId</h5>
        </div>
        <div class="card-body">
            <form id="@("form_Plan" + planId)" asp-page-handler="SavePlan" method="post">
                <input type="hidden" asp-for="Student.Plans.ToList()[i].PlanId" />
                <div class="row">
                    <div class="col">
                        <label asp-for="Student.Plans.ToList()[i].StartDate"></label>
                        <input asp-for="Student.Plans.ToList()[i].StartDate" class="form-control" />
                        <span asp-validation-for="Student.Plans.ToList()[i].StartDate"></span>
                    </div>
                    <div class="col">
                        <label asp-for="Student.Plans.ToList()[i].EndDate"></label>
                        <input asp-for="Student.Plans.ToList()[i].EndDate" class="form-control" />
                        <span asp-validation-for="Student.Plans.ToList()[i].EndDate"></span>
                    </div>
                </div>
            </form>
        </div>
        <div class="card-footer">
            <div class="float-right">
                <button type="submit" class="btn btn-primary" form="@("form_Plan" + planId)">Save</button>
            </div>
        </div>
    </div>
}

但似乎 SavePlan 页面处理程序中没有绑定任何内容:

[BindProperty]
public Student Student { get; set; }
.
.
.
public async Task<IActionResult> OnPostSavePlan(int planId)
{
    if (!ModelState.IsValid)
    {
        return Page();
    }

    /******************************
     *
     * Student.Plans is empty and planId is zero
     *
     *******************************/
    Plan plan = await _planContext.Plan.FirstAsync(p => p.PlanId == planId);

    _planContext.Attach(plan).State = EntityState.Modified;

    try
    {
        await _planContext.SaveChangesAsync();
    }
    catch (DbUpdateConcurrencyException)
    {
        if (!PlanExists(plan.PlanId))
        {
            return NotFound();
        }
        else
        {
            throw;
        }
    }

    return RedirectToPage("./Plans");
}

我究竟做错了什么?

标签: c#asp.net-corerazor-pages

解决方案


根据您的代码,因为您在剃刀页面中传递的是[0].PlanId,但您在 OnPostSavePlan 方法中收到的是planId. 如果您只需要接收planId,则需要更改表格。

<div class="card-body">
        <form id="@("form_Plan" + planId)" asp-page-handler="SavePlan" method="post">
            <input type="hidden" asp-for="@planId" />

根据您的要求,您似乎想通过一个计划列表。因此,您需要按以下步骤修改您的代码:

计划.cshtml:

<form id="form_Plan" asp-page-handler="SavePlan" method="post">
    @for (int i = 0; i < Model.Student.Plans.Count(); i++)
    {
        var planId = Model.Student.Plans.ToList()[i].PlanId.ToString();

        <div id="@("card_Plan" + planId)" class="card">
            <div class="card-header">
                <h5>Plan #@planId</h5>
            </div>
            <div class="card-body">
                <input type="hidden" asp-for="Student.Plans.ToList()[i].PlanId" />
                <div class="row">
                    <div class="col">
                        <label asp-for="Student.Plans.ToList()[i].StartDate"></label>
                        <input asp-for="Student.Plans.ToList()[i].StartDate" class="form-control" />
                        <span asp-validation-for="Student.Plans.ToList()[i].StartDate"></span>
                    </div>
                    <div class="col">
                        <label asp-for="Student.Plans.ToList()[i].EndDate"></label>
                        <input asp-for="Student.Plans.ToList()[i].EndDate" class="form-control" />
                        <span asp-validation-for="Student.Plans.ToList()[i].EndDate"></span>
                    </div>
                </div>
            </div>
        </div>
    }
    <div class="card-footer">
        <div class="float-right">
            <button type="submit" class="btn btn-primary" form="form_Plan">Save</button>
        </div>
    </div>
</form>

计划.cshtml.cs:

public class PlansModel : PageModel
{
    public IActionResult OnGet()
    {
        //for easy testing,I add the data manually
        Student = new Student()
        {
            Plans = new List<Plan>()
            {
                new Plan(){  PlanId=1, StartDate=DateTime.Parse("2019-8-7")},
                new Plan(){  PlanId=2, StartDate=DateTime.Parse("2019-4-7")},
                new Plan(){  PlanId=3, StartDate=DateTime.Parse("2019-6-7")}
            }
        };
        return Page();
    }

    [BindProperty]
    public Student Student { get; set; }
    public async Task<IActionResult> OnPostSavePlan(List<Plan> plans)
    {
        //...
    }
}

结果: 在此处输入图像描述

更新:

计划.cshtml:

@foreach (var plan in Model.Student.Plans)
{
    var planId = plan.PlanId.ToString();
    <div id="@("card_Plan" + planId)" class="card">
        <div class="card-header">
            <h5>Plan #@planId</h5>
        </div>
        <div class="card-body">
            <form id="@("form_Plan" + planId)" asp-page-handler="SavePlan" method="post">
                <input type="hidden" asp-for="@plan.PlanId" />
                <div class="row">
                    <div class="col">
                        <label asp-for="@plan.StartDate"></label>
                        <input asp-for="@plan.StartDate" class="form-control" />
                        <span asp-validation-for="@plan.StartDate"></span>
                    </div>
                    <div class="col">
                        <label asp-for="@plan.EndDate"></label>
                        <input asp-for="@plan.EndDate" class="form-control" />
                        <span asp-validation-for="@plan.EndDate"></span>
                    </div>
                </div>
            </form>
        </div>
        <div class="card-footer">
            <div class="float-right">
                <button type="submit" class="btn btn-primary" form="@("form_Plan" + planId)">Save</button>
            </div>
        </div>
    </div>
}

计划.cshtml.cs:

public async Task<IActionResult> OnPostSavePlan(Plan plan)
{
    //...
}

结果: 在此处输入图像描述


推荐阅读