【问题标题】:Saving an item in a collection in ASP.NET Core Razor Pages在 ASP.NET Core Razor 页面的集合中保存项目
【发布时间】:2020-12-07 00:02:00
【问题描述】:

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

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");
}

我做错了什么?

【问题讨论】:

    标签: c# asp.net-core razor-pages


    【解决方案1】:

    根据您的代码,因为您在剃须刀页面中传递的是[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" />
    

    根据您的要求,您似乎想要传递一个计划列表。所以你需要按照以下步骤修改你的代码:

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

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

    结果:

    更新:

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

    Plans.cshtml.cs:

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

    结果:

    【讨论】:

    • 感谢您的回复。我尝试了您的代码并且它有效,但是我想要每个计划的保存按钮(此项目的要求)。我使用我的原始代码并将我的页面处理程序更新为OnPostSavePlan(Plan plan),但plan.PlanId 仍然为0,其他属性为null(“StudentId”除外)。我还缺少什么?
    • 谢谢,Rena,它现在对我有用。快速跟进问题:如果我的处理程序中需要plan.StudentId 的值,我需要添加&lt;input type="hidden" asp-for="@plan.StudentId" /&gt;,对吗?我在页面处理程序中需要的任何其他属性也一样吗?
    • 我还注意到 Chrome DevTools 给了我很多“Found X elements with non-unique id”警告。我想这就是我开始使用asp-for 中的索引的原因。
    • 是的。如果您需要plan.StudentiId 的值,您需要一个隐藏字段将其传递给处理程序。处理程序保持不变。
    • 如果我的回答对你有帮助,可以接受。它也会帮助其他有类似问题的人。
    猜你喜欢
    • 2020-08-16
    • 1970-01-01
    • 2021-02-24
    • 1970-01-01
    • 1970-01-01
    • 2020-08-22
    • 2018-02-24
    • 2019-05-22
    • 1970-01-01
    相关资源
    最近更新 更多