您的位置:首页 > 编程语言 > ASP

ASP.NET Core 打造一个简单的图书馆管理系统(七)外借/阅览图书信息的增删改查

2019-02-01 17:49 866 查看

前言:

本系列文章主要为我之前所学知识的一次微小的实践,以我学校图书馆管理系统为雏形所作。

本系列文章主要参考资料:

微软文档:https://docs.microsoft.com/zh-cn/aspnet/core/getting-started/?view=aspnetcore-2.1&tabs=windows

《Pro ASP.NET MVC 5》、《锋利的 jQuery》

 

此系列皆使用 VS2017+C# 作为开发环境。如果有什么问题或者意见欢迎在留言区进行留言。 

项目 github 地址:https://github.com/NanaseRuri/LibraryDemo

 

 

本章内容:通过模态窗口确认是否提交表单、select 元素、表单提交数组、checkbox、关闭窗口前确认、EF 修改主键

 

 

 

一、外借/阅览图书信息首页

这里的实现和上一章大致一致,但这里我打算通过前面的 BookDetail 页面进入到这个页面:

首先创建一个视图模型同时保存 BookDetail 的信息并传递 IEnumerable<Book> 以便对对应 BookDetails 的外借/阅览图书信息进行展示:

public class BookEditModel
{
public BookDetails BookDetails { get; set; }
public IEnumerable<Book> Books { get; set; }
}

 

对应 BookDetail 的外借/阅览图书信息首页:

[Authorize(Roles = "Admin")]
public IActionResult Books(string isbn)
{
BookEditModel model = new BookEditModel()
{
Books = _context.Books.Where(b => b.ISBN == isbn),
BookDetails = _context.BooksDetail.FirstOrDefault(b => b.ISBN == isbn)
};
if (model.BookDetails==null)
{
TempData["message"] = "未找到目标书籍";
return RedirectToAction("BookDetails");
}
return View(model);
}

 

视图:

@using LibraryDemo.Models.DomainModels
@model BookEditModel

@{
ViewData["Title"] = "外借/阅览书籍信息";
Book temp = new Book();
}

<script>
function confirmDelete() {
var barcodes = document.getElementsByName("barcodes");
var message="确认删除";
for (i in barcodes) {
if (barcodes[i].checked) {
var book = barcodes[i].parentElement.nextElementSibling.firstElementChild.innerHTML;
message=message+"《"+book+"》";
}
}
message = message + "?";
if (confirm(message) == true) {
return true;
} else {
return false;
}
}
</script>

<style type="text/css">
tr + tr {
border-top: thin solid gray;
}

td + td {
padding-left: 100px;
}

.container {
width: 1200px;
}
</style>

<h2>《@Model.BookDetails.Name》</h2>
<br />

@if (TempData["message"] != null)
{
<p style="font-size: large;color:red" >@TempData["message"]</p>
<br />
<br />
}

<form asp-action="RemoveBooks" method="post">
<div>
<a class="btn btn-primary" asp-action="AddBook" asp-route-isbn="@Model.BookDetails.ISBN">添加外借书籍</a>
<button type="submit" class="btn btn-danger" onclick="return confirmDelete()"> 删除外借书籍</button>
</div>
<br />
<input type="hidden" name="isbn" value="@Model.BookDetails.ISBN"/>
<table>
<tbody>
<tr>
<td></td>
<td>@Html.LabelFor(b => temp.BarCode)</td>
<td>@Html.LabelFor(b => temp.Bookshelf)</td>
<td>@Html.LabelFor(b => temp.BorrowTime)</td>
<td>@Html.LabelFor(b => temp.MatureTime)</td>
<td>@Html.LabelFor(b => temp.AppointedLatestTime)</td>
<td>@Html.LabelFor(b => temp.State)</td>
<td>@Html.LabelFor(b => temp.Keeper)</td>
</tr>
@if (Model.Books.ToList().Count == 0)
{
<tr><td colspan="7">未有《@Model.BookDetails.Name》的外借/阅览书籍信息</td></tr>
}
@foreach (var book in Model.Books)
{
<tr>
<td><input type="checkbox" name="barcodes" value="@book.BarCode"/></td>
<td><a asp-action="EditBook" asp-route-barcode="@book.BarCode">@Html.DisplayFor(b => book.BarCode)</a></td>
<td>@Html.DisplayFor(b => book.BookshelfId)</td>
<td>@Html.DisplayFor(b => book.BorrowTime)</td>
<td>@Html.DisplayFor(b => book.MatureTime)</td>
<td>@Html.DisplayFor(b => book.AppointedLatestTime)</td>
<td>@Html.DisplayFor(b => book.State)</td>
<td>@Html.DisplayFor(b => book.Keeper.Name)</td>
</tr>
}
</tbody>
</table>
</form>

 

 结果:

 

 

二、添加的外借/阅览图书信息

在 21 行中使用了 Bind 特性,使在模型绑定过程中只绑定对应属性名的属性,防止了与其他数据的绑定。 Bind 特性中的属性名区分大小写,与表单中的 input 的 name 一一对应。

26 行使用 .AsNoTracking 告诉 EF 在查询时禁用更改跟踪提高性能,对不需要进行更改的数据的查询都可以带有该方法。

32 行对表单上传的数据进行检验以确认来自同一本书。

34 行中使用 Include 方法告诉 EF 使返回的书架包含架上书本的信息,使 bookshelf.Books 返回一个 ICollection 实例而不是空 ICollection 以将新的外借/阅览图书信息添加其中。

[Authorize(Roles = "Admin")]
public IActionResult AddBook(string isbn)
{
BookDetails bookDetails = _context.BooksDetail.FirstOrDefault(b => b.ISBN == isbn);
if (bookDetails == null)
{
return RedirectToAction("BookDetails", new { isbn = isbn });
}
Book book = new Book()
{
ISBN = bookDetails.ISBN,
Name = bookDetails.Name,
FetchBookNumber = bookDetails.FetchBookNumber
};
return View(book);
}

[HttpPost]
[ValidateAntiForgeryToken]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> AddBook([Bind("ISBN,Name,FetchBookNumber,BarCode,BookshelfId,State")]Book book)
{
if (ModelState.IsValid)
{
BookDetails bookDetails = _context.BooksDetail.FirstOrDefault(b => b.ISBN == book.ISBN);
Book existBook = _context.Books.AsNoTracking().FirstOrDefault(b => b.BarCode == book.BarCode);
if (existBook != null)
{
TempData["message"] = $"已有二维码为{book.BarCode}的书籍《{existBook.Name}》";
return RedirectToAction("AddBook", new {isbn = book.ISBN});
}
if (bookDetails.Name == book.Name)
{
Bookshelf bookshelf = _context.Bookshelves.Include(b=>b.Books).FirstOrDefault(b => b.BookshelfId == book.BookshelfId);
if (bookshelf != null)
{
book.Sort = bookshelf.Sort;
book.Location = bookshelf.Location;
bookshelf.Books.Add(book);
bookshelf.MaxFetchNumber = bookshelf.Books.Max(b => b.FetchBookNumber);
bookshelf.MinFetchNumber = bookshelf.Books.Min(b => b.FetchBookNumber);
}
await _context.Books.AddAsync(book);
await _context.SaveChangesAsync();
TempData["message"] = $"《{book.Name}》 {book.BarCode} 添加成功";
return RedirectToAction("Books", new { isbn = book.ISBN });
}
}
return View(book);
}

 

 视图:

@using LibraryDemo.Models.DomainModels
@model LibraryDemo.Models.DomainModels.Book

@{
ViewData["Title"] = "AddBook";
}

<script>
window.onload = function () {
$("input").addClass("form-control");
}
window.onbeforeunload = function () {
return "您的数据未保存,确定退出?";
}
function removeOnbeforeunload() {
window.onbeforeunload = "";
}
</script>

<h2>@($"为《{Model.Name}》添加借阅/阅览书籍信息")</h2>
<br />
<br />
@if (TempData["message"] != null)
{
<p class="text-primary">@TempData["message"]</p>
<br />
<br />
}

@Html.ValidationSummary(false, "", new { @class = "text-danger" })
<form asp-action="AddBook" method="post">
<div class="form-group">
@Html.LabelFor(b => b.ISBN)
<input type="text" value="@Model.ISBN" readonly="readonly" name="@nameof(Model.ISBN)" />
</div>
<div class="form-group">
@Html.LabelFor(b => b.Name)
<input type="text" value="@Model.Name" readonly="readonly" name="@nameof(Model.Name)" />
</div>
<div class="form-group">
@Html.LabelFor(b => b.FetchBookNumber)
<input type="text" value="@Model.FetchBookNumber" readonly="readonly" name="@nameof(Model.FetchBookNumber)" />
</div>
<div class="form-group">
@Html.LabelFor(b => Model.BarCode)
@Html.EditorFor(b => Model.BarCode)
</div>
<div class="form-group">
@Html.LabelFor(b => Model.BookshelfId)
@Html.EditorFor(b => Model.BookshelfId)
</div>
<div class="form-group">
@Html.LabelFor(b => Model.State)
@Html.DropDownListFor(b=>Model.State,Enum.GetValues(typeof(BookState)).Cast<Enum>().Select(state =>
{
string enumVal = Enum.GetName(typeof(BookState), state);
string displayVal;
switch (enumVal)
{
case "Normal":
displayVal = "可借阅";
break;
case "Readonly":
displayVal = "馆内阅览";
break;
case "Borrowed":
displayVal = "已借出";
break;
case "ReBorrowed":
displayVal = "被续借";
break;
case "Appointed":
displayVal = "被预约";
break;
default:
displayVal = "";
break;
}
return new SelectListItem()
{
Text=displayVal,
Value = enumVal
};
}))
</div>
<div class="form-group"></div>
<input type="submit" class="btn-success" onclick="removeOnbeforeunload()" />
</form>

 

 

 

三、移除外借/阅览图书信息

 此处实现与之前移除书籍信息大致一致,但额外接受一个 isbn 参数用来返回原 isbn 的外借/阅览图书信息首页:

[Authorize(Roles = "Admin")]
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> RemoveBooks(IEnumerable<string> barcodes, string isbn)
{
StringBuilder sb = new StringBuilder();
foreach (var barcode in barcodes)
{
Book book = _context.Books.First(b => b.BarCode == barcode);
_context.Books.Remove(book);
sb.AppendLine($"{book.BarCode} 移除成功");
}
await _context.SaveChangesAsync();
TempData["message"] = sb.ToString();
return RedirectToAction("Books", new { isbn = isbn });
}

 

 

四、增删总结果:

 

 

 

五、编辑借阅/阅览书籍信息:

在此设置 BarCode 可以被修改,由于修改主键时会导致 EF 的映射失败,因此EF 不支持直接修改主键,但是可以先将原数据删除再进行添加变相修改主键。

POST 的方法中额外接受一个 BarCode 用来保留原书籍信息。

[Authorize(Roles = "Admin")]
public IActionResult EditBook(string barcode)
{
Book book = _context.Books.First(b => b.BarCode == barcode);
return View(book);
}

[HttpPost]
[Authorize(Roles = "Admin")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> EditBook(string oldBarCode,[Bind("BarCode,BookshelfId,BorrowTime,Name,KeeperId,AppointedLatestTime")]Book book)
{
if (ModelState.IsValid)
{
Book oldBook = _context.Books.FirstOrDefault(b => b.BarCode == oldBarCode);
if (oldBook == null)
{
ViewBag["message"] = $"不存在二维码为{oldBarCode}的书籍";
return RedirectToAction("BookDetails");
}

if (oldBook.Name == book.Name)
{
book.ISBN = oldBook.ISBN;
book.FetchBookNumber = oldBook.FetchBookNumber;
Bookshelf bookshelf = _context.Bookshelves.Include(b => b.Books).FirstOrDefault(b => b.BookshelfId == book.BookshelfId);
if (bookshelf != null)
{
book.Sort = bookshelf.Sort;
book.Location = bookshelf.Location;
bookshelf.Books.Remove(oldBook);
bookshelf.Books.Add(book);
}

_context.Books.Remove(oldBook);
_context.Books.Add(book);
await _context.SaveChangesAsync();
TempData["message"] = "修改成功";
return RedirectToAction("Books", new { isbn = oldBook.ISBN });
}
}
return View(book);
}

 

 

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐