[英]ASP.NET Core MVC cannot bind checkboxlist
环境是VS2019,ASP.NET Core MVC 2.1。 我对此很陌生。 在发布时, Book
对象的BookCategory
列表为空。 我无法弄清楚哪个(或哪些)部分是错误的。
有 3 个模型, Book
, Category
和连接模型BookCategory
。 Book
和Category
是多对多的,关系存储在BookCategory
表中。
public class Book
{
public int BookId { get; set; }
[Required]
public string Title { get; set; }
public ICollection<BookCategory> BookCategories { get; set; }
}
public class Category
{
public int CategoryId { get; set; }
public string CategoryName { get; set; }
public ICollection<BookCategory> BookCategories { get; set; }
}
public class BookCategory
{
public int BookId { get; set; }
public Book Book { get; set; }
public int CategoryId { get; set; }
public Category Category { get; set; }
public bool IsSelected { get; set; }
}
BooksController
如下所示。 GetBookAndBookCategoryData
将获得一个带有关联BookCategory
列表的Book
对象。 PopulateBookCategoriesList
将向视图包添加一个Category
列表。
[HttpGet]
public async Task<IActionResult> Book(int? id)
{
int bookId = id.GetValueOrDefault();
await PopulateBookCategoriesList();
var book = await GetBookAndBookCategoryData(bookId);
return View(book);
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Book(int? id, Book book)
{
id = id ?? 0;
if (id != book.BookId) // ?? means coalesce, it takes the first non-null value.
{
return NotFound();
}
var category = _context.Categories;
if (ModelState.IsValid)
{
// if create a new book
if (id == 0)
{
_context.Add(book);
await _context.SaveChangesAsync();
foreach (var bc in book.BookCategories)
{
var bcat = new BookCategory() { BookId = book.BookId, CategoryId = bc.CategoryId, IsSelected = bc.IsSelected };
_context.Add(bcat);
}
await _context.SaveChangesAsync();
}
else
{
_context.Update(book);
foreach (var i in book.BookCategories)
{
var bcat = _context.BookCategories.FirstOrDefault(bc => bc.BookId == book.BookId && bc.CategoryId == i.CategoryId);
bcat.IsSelected = i.IsSelected;
_context.Update(bcat);
}
}
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(book);
}
private async Task<Book> GetBookAndBookCategoryData(int BookId = 0)
{
var book = new Book();
var category = await _context.Categories.ToListAsync();
if (BookId == 0)
{
book.BookCategories = new List<BookCategory>();
foreach (var c in category)
{
book.BookCategories.Add(new BookCategory() { BookId = BookId, CategoryId = c.CategoryId, IsSelected = false });
}
}
else
{
book = await _context.Books.FindAsync(BookId);
if (book.BookCategories is null || book.BookCategories.Count == 0)
{
book.BookCategories = new List<BookCategory>();
foreach (var c in _context.Categories)
{
book.BookCategories.Add(new BookCategory() { BookId = book.BookId, CategoryId = c.CategoryId, IsSelected = false });
}
}
}
return book;
}
private async Task PopulateBookCategoriesList()
{
var list = await _context.Categories.ToListAsync();
ViewBag.CategoryList = list;
}
在 DBContext 中:
public class ApplicationDbContext : IdentityDbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public DbSet<MvcTest.Models.Book> Books { get; set; }
public DbSet<MvcTest.Models.Category> Categories { get; set; }
public DbSet<MvcTest.Models.BookCategory> BookCategories { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Category>().HasData(
new Category { CategoryId = 1, CategoryName = "AAA" },
new Category { CategoryId = 2, CategoryName = "BBB" },
new Category { CategoryId = 3, CategoryName = "CCC" },
new Category { CategoryId = 4, CategoryName = "DDD" },
new Category { CategoryId = 5, CategoryName = "EEE" },
new Category { CategoryId = 6, CategoryName = "FFF" },
new Category { CategoryId = 7, CategoryName = "GGG" }
);
modelBuilder.Entity<BookCategory>()
.HasKey(bc => new { bc.BookId, bc.CategoryId });
modelBuilder.Entity<BookCategory>()
.HasOne(bc => bc.Book)
.WithMany(b => b.BookCategories)
.HasForeignKey(bc => bc.BookId);
modelBuilder.Entity<BookCategory>()
.HasOne(bc => bc.Category)
.WithMany(c => c.BookCategories)
.HasForeignKey(bc => bc.CategoryId);
base.OnModelCreating(modelBuilder);
}
}
风景:
@model MvcTest.Models.Book
@{
ViewData["Title"] = "Create";
}
<h2>Create</h2>
<h4>Book</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Book">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="BookId" class="control-label"></label>
<input asp-for="BookId" disabled="disabled" class="form-control" />
<input asp-for="BookId" class="form-control invisible" />
<span asp-validation-for="BookId" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Title" class="control-label"></label>
<input asp-for="Title" class="form-control" />
<span asp-validation-for="Title" class="text-danger"></span>
</div>
<div class="form-group">
@{ var categoryList = ViewBag.CategoryList as List<Category>; }
@foreach (var bc in Model.BookCategories)
{
<div class="col-md-3 col-sm-6">
<div class="checkbox">
<label>
<input type="checkbox" checked="@bc.IsSelected" name="BookCategories"
value="@bc.CategoryId">@categoryList.Where(c => c.CategoryId == bc.CategoryId).SingleOrDefault().CategoryName
</label>
</div>
</div>
}
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
这是很多代码,我感谢您的时间和耐心。
您的复选框的名称是SelectedCategoryValues
,当您提交时,您需要一个List<int> SelectedCategoryValues
on action 参数来存储所有选定类别的 id 列表。并且您无法使用表单提交直接映射到book.BookCategories
。
尝试使用以下代码在Post
操作中填充Book
对象的BookCategory
列表:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Book(int? id, List<int> SelectedCategoryValues, Book book)
{
var bookCategories = new List<BookCategory>();
foreach (var c in _context.Categories)
{
bookCategories.Add(
new BookCategory() { BookId = book.BookId, CategoryId = c.CategoryId, IsSelected = SelectedCategoryValues.Contains(c.CategoryId) ? true : false }
);
}
book.BookCategories = bookCategories;
//...
}
你是如何从数据库中检索它的? 如果您希望书对象和类别对象包含在模型中,则需要添加一个
.Include(x => x.Book)
.Include(x => x.Category)
书对象也包含在从数据库返回的对象中
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.