Asp .Net Core 3.1 Razor 页面:复杂模型绑定
Posted
技术标签:
【中文标题】Asp .Net Core 3.1 Razor 页面:复杂模型绑定【英文标题】:Asp .Net Core 3.1 Razor Page: Complex model binding 【发布时间】:2020-11-16 22:24:03 【问题描述】:我在数据绑定和 Razor 页面上苦苦挣扎
我无法找到解决方案。可能我问的问题不正确。 所以我希望你能帮我指出正确的方向。
我想要一个页面来创建预订以收集所有必要的数据,以便在一切完成后将其发布到 Web api。
在该页面上,我想为 wooking 收集必要的数据,并希望将 x 预订详细信息添加到预订中。
数据模型
public class Booking
[Key]
public int Id get; set;
public string Reference get; set;
public List<BookingDetail> BookingDetails get; set;
public class BookingDetail
[Key]
public int Id get; set;
public int Pieces get; set;
public string Marks get; set;
我想做的是为预订创建一个创建页面。 到目前为止,我遵循了这个说明,它正在工作Link
这个缺失的部分是我想在同一个 Razor 页面上添加新的预订详细信息。
所以我想查看所有添加的预订详细信息的列表,并且我希望有文本框来添加新的预订详细信息。
我的想法是执行以下操作,但由于 Booking 为空,我收到了 System.NullReferenceException
:
@page
@model Onlinebooking.Web.Pages.BookingModel
@
ViewData["Title"] = "Booking";
<h1>Booking4</h1>
<form method="post">
Reference: <Input asp-for="Booking.Reference" /><br />
Pieces: <input asp-for="Booking.BookingDetails[0].Pieces" /><br />
Marks: <input asp-for="Booking.BookingDetails[0].Marks" /><br />
<br />
<input type="submit" value="submit" />
</form>
<form method="post" asp-page-handler="DeleteBookingDetails">
@for (var i = 0; i < @Model.Booking.BookingDetails.Count(); i++)
@html.LabelFor(x => x.Booking.BookingDetails[i].Pieces)
@Html.LabelFor(x => x.Booking.BookingDetails[i].Marks)
</form>
是否有可能在一个页面上完成所有这些操作,还是应该换个方向?
感谢您的帮助!
【问题讨论】:
这是可能的;您甚至可以使用模板来定义正确的EditorFor
...顺便说一句,为什么@Model.Booking.BookingDetails.Count()-1
中的-1
?
这可能很难,因为您正试图将数据模型用作视图模型。它们确实应该是不同的东西(可能具有许多相同的属性)。您在 UI/View 上看到的所有内容都应该在 ViewModel 中具有一个属性,但并非所有这些属性都会最终出现在您的数据库中。
@Stefan 我看到-1
是一个错误,没有任何意义。我编辑了帖子。
【参考方案1】:
这是一个添加和删除 BookingDetai 的演示:
cshtml:
<form method="post">
<Input asp-for="Booking.Id" hidden />
Reference: <Input asp-for="Booking.Reference" /><br />
Pieces: <input name="Booking.BookingDetails[@Model.Booking.BookingDetails.Count()].Pieces" /><br />
Marks: <input name="Booking.BookingDetails[@Model.Booking.BookingDetails.Count()].Marks" /><br />
<br />
<input type="submit" value="submit" asp-page-handler="AddBookingDetails"/>
<div hidden>
@for (var i = 0; i < @Model.Booking.BookingDetails.Count(); i++)
<input asp-for="@Model.Booking.BookingDetails[i].Id" hidden />
<input asp-for="@Model.Booking.BookingDetails[i].Pieces" hidden />
<input asp-for="@Model.Booking.BookingDetails[i].Marks" hidden />
</div>
</form>
<table>
<thead>
<tr>
<th><label class="control-label">Pieces</label></th>
<th><label class="control-label">Marks</label></th>
<th><label class="control-label">Action</label></th>
</tr>
</thead>
<tbody>
@for (var i = 0; i < @Model.Booking.BookingDetails.Count(); i++)
<tr>
<form method="post" >
<div hidden>
@for (var j = 0; j < @Model.Booking.BookingDetails.Count(); j++)
<input asp-for="@Model.Booking.BookingDetails[j].Id" hidden />
<input asp-for="@Model.Booking.BookingDetails[j].Pieces" hidden />
<input asp-for="@Model.Booking.BookingDetails[j].Marks" hidden />
</div>
<td>@Model.Booking.BookingDetails[i].Pieces</td>
<input name="Booking.Id" hidden value="@Model.Booking.Id" />
<input name="Booking.Reference" hidden value="@Model.Booking.Reference" />
<input name="BookingDetail.Id" hidden value="@Model.Booking.BookingDetails[i].Id" />
<td>@Model.Booking.BookingDetails[i].Marks</td>
<td><button asp-page-handler="DeleteBookingDetails">delete</button></td>
</form>
</tr>
</tbody>
</table>
cshtml.cs(我用简单的数据来测试一下):
public class CreateBookingModel : PageModel
[BindProperty]
public Booking Booking get; set;
[BindProperty]
//BookingDetail is used to delete BookingDetail
public BookingDetail BookingDetail get; set;
public static int count;
public ActionResult OnGet()
List<BookingDetail> list = new List<BookingDetail> new BookingDetail Id = 1, Pieces = 2, Marks = "m1" , new BookingDetail Id = 2, Pieces = 1, Marks = "m2" ;
Booking = new Booking Id = 1, Reference = "r", BookingDetails = list ;
count = 2;
return Page();
public ActionResult OnPostAddBookingDetails()
Booking.BookingDetails[Booking.BookingDetails.Count()-1].Id = ++count;
return Page();
public ActionResult OnPostDeleteBookingDetails()
Booking.BookingDetails.RemoveAll(b => b.Id == BookingDetail.Id);
return Page();
结果:
【讨论】:
感谢您的评论!我学到了很多。但是我在删除列表的一行时遇到了问题。当我通过在OnPostDeleteBookingDetails
中执行Booking.BookingDetails.RemoveAt(1);
删除时,我看到了奇怪的行为。您能否将删除功能添加到您的示例中?
我已经更新了绑定 Booking.Id 和您要添加或删除的 BookingDetail 的答案
我认为您的代码现在已损坏。添加和删除不起作用。我很抱歉。我无法弄清楚如何让它工作......
你可以得到Booking Id和你要添加或删除的BookingDetail,然后你可以使用Booking Id在数据库中找到Booking,并添加或删除它的BookingDetail。我只是写了一个演示到模型绑定所需的数据,而无需编写从数据库中添加或删除数据。
知道了。我真的很喜欢您的代码将数据添加到模型而不将其写入数据库,因为我不需要它,因为我想将数据发布到 webapi。无论如何:在您修改代码后,添加数据不起作用,也不能删除。而且我不知道如何解决它。我们非常接近有一个非常好的解决方案,可以完全满足我的需求。那么有没有机会从您的第一个代码版本中删除添加的数据中的数据?我想一个问题是,当数据“仅”写入模型时,还没有设置 ID...【参考方案2】:
在您的问题中,我也遇到了很多困难。
您遇到的第一个问题是在 CSHTML.CS 文件中。初始化变量将解决这个问题。
public class BookingModel : PageModel
private readonly DataDbContext _context;
public BookingModel(DataDbContext context)
_context = context;
public List<Booking> Bookings get; set; = new List<Booking>();
public Booking Booking get; set; = new Booking();
public BookingDetail BookingDetail get; set; = new BookingDetail();
public void OnGet()
Bookings = _context.Bookings.Include(x => x.BookingDetails).ToList();
在 CSHTML 方面,我会稍微修改您引用标签和打印 FOR 循环的方式。
<form method="post" asp-page-handler="DeleteBookingDetails">
<table>
<thead>
<tr>
<th><label asp-for="BookingDetail.Pieces" class="control-label"></label></th>
<th><label asp-for="BookingDetail.Marks" class="control-label"></label></th>
</tr>
</thead>
<tbody>
@foreach (var booking in Model.Bookings)
foreach (var bookingDetail in booking.BookingDetails)
<tr>
<td>@bookingDetail.Pieces</td>
<td>@bookingDetail.Marks</td>
</tr>
</tbody>
</table>
我没有修改 Booking 或 BookingDetail。
我相信您将能够从这里找出其余的功能。
【讨论】:
以上是关于Asp .Net Core 3.1 Razor 页面:复杂模型绑定的主要内容,如果未能解决你的问题,请参考以下文章
ASP.NET Core 3.1 Razor 将字符串转换为日期时间
ASP.NET Core 3.1 Razor 页面路由不明确匹配异常
Asp.net Core 3.1-如何从控制器返回到 Razor 页面?
在 ASP.net core 3.1 Razor Pages 中打印 PDF
创建基于ASP.NET core 3.1 的RazorPagesMovie项目-应用模型类配合基架生成工具生成Razor页面