问题描述
我不了解如何正确绑定集合中的单个项目。在我的项目中,学生可以使用以下模型制定多个计划:
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>
}
更新:
Plans.cshtml:
public async Task<IActionResult> OnPostSavePlan(Plan plan)
{
//...
}
Plans.cshtml.cs:
strings <FILE NAME> | grep "Version = <VERSION STRING>" > /dev/null