将项目保存到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; }
}

我在页面上用自己的“保存”按钮列出了每个计划。我以为我按照this Learn Razor Pages post正确使用了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");
}

我在做什么错了?

解决方法

根据您的代码,因为在剃刀页面中传递的是planId,但是在OnPostSavePlan方法中传递的是planId。如果您只需要接收<div class="card-body"> <form id="@("form_Plan" + planId)" asp-page-handler="SavePlan" method="post"> <input type="hidden" asp-for="@planId" /> ,则需要更改表格。

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

根据您的要求,看来您想传递一个计划清单。因此,您需要按照以下步骤修改代码:

Plans.cshtml:

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)
    {
        //...
    }
}

Plans.cshtml.cs:

@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>
}

结果: enter image description here

更新

Plans.cshtml:

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

Plans.cshtml.cs:

strings <FILE NAME> | grep "Version = <VERSION STRING>" > /dev/null

结果: enter image description here