[英]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.