如何将输入字段绑定到两个不同的模型?
How to bind input fields to two different models?
我正在构建图书列表应用程序。它有以下型号:
- Book (int Id, string Title, string Type, int MinimumAge) [Id=Key, Title=Required, Type=Required, MinimumAge=Required]
- 流派(int Id, string Name) [大师table]
- BookGenre (int BookId, int GenreId) [无键实体]
- CreateViewModel(书籍书籍,IEnumerable 流派)
现在我正在处理 CREATE 操作。
控制器代码 (BookController.cs)
此控制器的 Create() POST 方法不完整。
using BookList.Data;
using BookList.Models;
using Microsoft.AspNetCore.Mvc;
namespace BookList.Controllers
{
public class BookController : Controller
{
private readonly ApplicationDbContext db;
public BookController(ApplicationDbContext db)
{
this.db = db;
}
// READ (Get)
public IActionResult Index()
{
IEnumerable<Book> bookList = db.Books;
return View(bookList);
}
// CREATE (Get)
public IActionResult Create()
{
// Create custom view model
CreateViewModel model = new CreateViewModel();
model.Book = new Book();
model.Genre = new Genre();
return View(model);
}
// CREATE (Post)
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Create(CreateViewModel obj)
{
// Write your code here
return RedirectToAction("Index");
}
}
}
查看代码 (Create.cshtml):
@model CreateViewModel
<div class="row">
<div class="border mt-4">
<div class="row py-2">
<h2 class="text-primary">Add a New Book</h2>
<hr />
</div>
<form asp-action="Create">
<div asp-validation-summary="All" class="text-danger"></div>
@* Title *@
<div class="form-group mb-2">
<label asp-for="Book.Title"></label><br />
<input asp-for="Book.Title" class="form-control" />
<span asp-validation-for="Book.Title" class="text-danger"></span>
</div>
@* Genre *@
<div class="form-group mb-2">
<label>Genre</label><br/>
<div>
@foreach(var genre in Model.Genres)
{
<label for=@genre.Id>@genre.Name</label>
<input type="checkbox" id=@genre.Id value=@genre.Name />
}
</div>
</div>
@* Type(Fiction/Non-Fiction) *@
<div class="form-group mb-2">
<label asp-for="Book.Type"></label><br />
<div>
Fiction <input type="radio" asp-for="Book.Type" value="Fiction" />
Non-Fiction <input type="radio" asp-for="Book.Type" value="Non-Fiction"/>
</div>
<span asp-validation-for="Book.Type" class="text-danger"></span>
</div>
@* Minimum Age(dropdown) *@
<div class="form-group mb-2">
<label asp-for="Book.MinimumAge" class="control-label"></label>
<select asp-for="Book.MinimumAge" class="form-control">
<option value=8>8</option>
<option value=12>12</option>
<option value=16>16</option>
<option value=18>18</option>
</select>
<span asp-validation-for="Book.MinimumAge" class="text-danger"></span>
</div>
<div class="form-group mb-2">
<input type="submit" value="Add" class="btn btn-primary" />
</div>
</form>
</div>
</div>
@*Cient-side validation scripts*@
@section Scripts {
<partial name="_ValidationScriptsPartial" />
}
假设用户输入以下详细信息并单击创建:
Title="XYZ", Genres="Action,Adventure", Type="Fiction", 最低年龄=12
然后,我想 (auto-id, "XYZ","Fiction",12) 进入本书 table。并且,(auto-id,1) 和 (auto-id,2) 进入 BookGenre table.
流派大师 table 包含以下详细信息供您参考。 BookGenre table 是一个 Keyless 实体。
首先要知道模型绑定系统是通过名称属性绑定数据的。
从视图设计中我可以看到您的 CreateViewModel
包含 IEnumerable<Genre> Genres
,因此前端应添加如下名称:Genres[index].PropertyName
。但是随后你会发现一个问题,如果你要选择不连续的复选框,你只会收到连续的值而错过不连续的。
因此建议您也创建一个 属性 List<string> GenresList
并在前端添加 name="GenresList"
。
这是一个完整的工作演示:
型号:
public class Book
{
public int Id { get; set; }
public int MininumAge { get; set; }
public string Title { get; set; }
public string Type { get; set; }
public ICollection<Genre>? Genres { get; set; }
}
public class Genre
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Book>? Books { get; set; }
}
public class CreateViewModel
{
public Book Book { get; set; }
public List<Genre>? Genres { get; set; }
public List<string> GenresList { get; set; }
}
查看:
@model CreateViewModel
<div class="row">
<div class="border mt-4">
<div class="row py-2">
<h2 class="text-primary">Add a New Book</h2>
<hr />
</div>
<form asp-action="Create">
<div asp-validation-summary="All" class="text-danger"></div>
@* Title *@
<div class="form-group mb-2">
<label asp-for="Book.Title"></label><br />
<input asp-for="Book.Title" class="form-control" />
<span asp-validation-for="Book.Title" class="text-danger"></span>
</div>
@* Genre *@
<div class="form-group mb-2">
<label>Genre</label><br/>
<div>
@foreach(var genre in Model.Genres)
{
<label for=@genre.Id>@genre.Name</label> @* add name here*@
<input type="checkbox" id=@genre.Id value=@genre.Name name="GenresList"/>
}
</div>
</div>
@* Type(Fiction/Non-Fiction) *@
<div class="form-group mb-2">
<label asp-for="Book.Type"></label><br />
<div>
Fiction <input type="radio" asp-for="Book.Type" value="Fiction" />
Non-Fiction <input type="radio" asp-for="Book.Type" value="Non-Fiction"/>
</div>
<span asp-validation-for="Book.Type" class="text-danger"></span>
</div>
@* Minimum Age(dropdown) *@
<div class="form-group mb-2">
<label asp-for="Book.MininumAge" class="control-label"></label>
<select asp-for="Book.MininumAge" class="form-control">
<option value=8>8</option>
<option value=12>12</option>
<option value=16>16</option>
<option value=18>18</option>
</select>
<span asp-validation-for="Book.MininumAge" class="text-danger"></span>
</div>
<div class="form-group mb-2">
<input type="submit" value="Add" class="btn btn-primary" />
</div>
</form>
</div>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
控制器:
public class BooksController : Controller
{
private readonly MvcProj6_0Context _context;
public BooksController(MvcProj6_0Context context)
{
_context = context;
}
// GET: Books/Create
public IActionResult Create()
{
CreateViewModel model = new CreateViewModel();
model.Book = new Book();
model.Genres = _context.Genre.ToList();
return View(model);
}
// POST: Books/Create
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(CreateViewModel obj)
{
if (ModelState.IsValid)
{
var genres = new List<Genre>();
foreach (var item in obj.GenresList)
{
genres.Add(_context.Genre.Where(a => a.Name == item).First());
}
obj.Book.Genres = genres;
_context.Add(obj.Book);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(obj);
}
}
注:
在 .NET 6 中,它在项目文件中包含 <Nullable>enable</Nullable>
元素,这使得 属性 non-nullable。 non-nullable 属性 必须要有,否则ModelState无效。您可以使用 ?
或在模型设计中初始化 属性 以跳过所需的验证。
我正在构建图书列表应用程序。它有以下型号:
- Book (int Id, string Title, string Type, int MinimumAge) [Id=Key, Title=Required, Type=Required, MinimumAge=Required]
- 流派(int Id, string Name) [大师table]
- BookGenre (int BookId, int GenreId) [无键实体]
- CreateViewModel(书籍书籍,IEnumerable 流派)
现在我正在处理 CREATE 操作。
控制器代码 (BookController.cs)
此控制器的 Create() POST 方法不完整。
using BookList.Data;
using BookList.Models;
using Microsoft.AspNetCore.Mvc;
namespace BookList.Controllers
{
public class BookController : Controller
{
private readonly ApplicationDbContext db;
public BookController(ApplicationDbContext db)
{
this.db = db;
}
// READ (Get)
public IActionResult Index()
{
IEnumerable<Book> bookList = db.Books;
return View(bookList);
}
// CREATE (Get)
public IActionResult Create()
{
// Create custom view model
CreateViewModel model = new CreateViewModel();
model.Book = new Book();
model.Genre = new Genre();
return View(model);
}
// CREATE (Post)
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Create(CreateViewModel obj)
{
// Write your code here
return RedirectToAction("Index");
}
}
}
查看代码 (Create.cshtml):
@model CreateViewModel
<div class="row">
<div class="border mt-4">
<div class="row py-2">
<h2 class="text-primary">Add a New Book</h2>
<hr />
</div>
<form asp-action="Create">
<div asp-validation-summary="All" class="text-danger"></div>
@* Title *@
<div class="form-group mb-2">
<label asp-for="Book.Title"></label><br />
<input asp-for="Book.Title" class="form-control" />
<span asp-validation-for="Book.Title" class="text-danger"></span>
</div>
@* Genre *@
<div class="form-group mb-2">
<label>Genre</label><br/>
<div>
@foreach(var genre in Model.Genres)
{
<label for=@genre.Id>@genre.Name</label>
<input type="checkbox" id=@genre.Id value=@genre.Name />
}
</div>
</div>
@* Type(Fiction/Non-Fiction) *@
<div class="form-group mb-2">
<label asp-for="Book.Type"></label><br />
<div>
Fiction <input type="radio" asp-for="Book.Type" value="Fiction" />
Non-Fiction <input type="radio" asp-for="Book.Type" value="Non-Fiction"/>
</div>
<span asp-validation-for="Book.Type" class="text-danger"></span>
</div>
@* Minimum Age(dropdown) *@
<div class="form-group mb-2">
<label asp-for="Book.MinimumAge" class="control-label"></label>
<select asp-for="Book.MinimumAge" class="form-control">
<option value=8>8</option>
<option value=12>12</option>
<option value=16>16</option>
<option value=18>18</option>
</select>
<span asp-validation-for="Book.MinimumAge" class="text-danger"></span>
</div>
<div class="form-group mb-2">
<input type="submit" value="Add" class="btn btn-primary" />
</div>
</form>
</div>
</div>
@*Cient-side validation scripts*@
@section Scripts {
<partial name="_ValidationScriptsPartial" />
}
假设用户输入以下详细信息并单击创建:
Title="XYZ", Genres="Action,Adventure", Type="Fiction", 最低年龄=12
然后,我想 (auto-id, "XYZ","Fiction",12) 进入本书 table。并且,(auto-id,1) 和 (auto-id,2) 进入 BookGenre table.
流派大师 table 包含以下详细信息供您参考。 BookGenre table 是一个 Keyless 实体。
首先要知道模型绑定系统是通过名称属性绑定数据的。
从视图设计中我可以看到您的 CreateViewModel
包含 IEnumerable<Genre> Genres
,因此前端应添加如下名称:Genres[index].PropertyName
。但是随后你会发现一个问题,如果你要选择不连续的复选框,你只会收到连续的值而错过不连续的。
因此建议您也创建一个 属性 List<string> GenresList
并在前端添加 name="GenresList"
。
这是一个完整的工作演示:
型号:
public class Book
{
public int Id { get; set; }
public int MininumAge { get; set; }
public string Title { get; set; }
public string Type { get; set; }
public ICollection<Genre>? Genres { get; set; }
}
public class Genre
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Book>? Books { get; set; }
}
public class CreateViewModel
{
public Book Book { get; set; }
public List<Genre>? Genres { get; set; }
public List<string> GenresList { get; set; }
}
查看:
@model CreateViewModel
<div class="row">
<div class="border mt-4">
<div class="row py-2">
<h2 class="text-primary">Add a New Book</h2>
<hr />
</div>
<form asp-action="Create">
<div asp-validation-summary="All" class="text-danger"></div>
@* Title *@
<div class="form-group mb-2">
<label asp-for="Book.Title"></label><br />
<input asp-for="Book.Title" class="form-control" />
<span asp-validation-for="Book.Title" class="text-danger"></span>
</div>
@* Genre *@
<div class="form-group mb-2">
<label>Genre</label><br/>
<div>
@foreach(var genre in Model.Genres)
{
<label for=@genre.Id>@genre.Name</label> @* add name here*@
<input type="checkbox" id=@genre.Id value=@genre.Name name="GenresList"/>
}
</div>
</div>
@* Type(Fiction/Non-Fiction) *@
<div class="form-group mb-2">
<label asp-for="Book.Type"></label><br />
<div>
Fiction <input type="radio" asp-for="Book.Type" value="Fiction" />
Non-Fiction <input type="radio" asp-for="Book.Type" value="Non-Fiction"/>
</div>
<span asp-validation-for="Book.Type" class="text-danger"></span>
</div>
@* Minimum Age(dropdown) *@
<div class="form-group mb-2">
<label asp-for="Book.MininumAge" class="control-label"></label>
<select asp-for="Book.MininumAge" class="form-control">
<option value=8>8</option>
<option value=12>12</option>
<option value=16>16</option>
<option value=18>18</option>
</select>
<span asp-validation-for="Book.MininumAge" class="text-danger"></span>
</div>
<div class="form-group mb-2">
<input type="submit" value="Add" class="btn btn-primary" />
</div>
</form>
</div>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
控制器:
public class BooksController : Controller
{
private readonly MvcProj6_0Context _context;
public BooksController(MvcProj6_0Context context)
{
_context = context;
}
// GET: Books/Create
public IActionResult Create()
{
CreateViewModel model = new CreateViewModel();
model.Book = new Book();
model.Genres = _context.Genre.ToList();
return View(model);
}
// POST: Books/Create
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(CreateViewModel obj)
{
if (ModelState.IsValid)
{
var genres = new List<Genre>();
foreach (var item in obj.GenresList)
{
genres.Add(_context.Genre.Where(a => a.Name == item).First());
}
obj.Book.Genres = genres;
_context.Add(obj.Book);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(obj);
}
}
注:
在 .NET 6 中,它在项目文件中包含 <Nullable>enable</Nullable>
元素,这使得 属性 non-nullable。 non-nullable 属性 必须要有,否则ModelState无效。您可以使用 ?
或在模型设计中初始化 属性 以跳过所需的验证。