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

  • A+
所属分类:腾讯分分彩

前言:

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

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

微软文档: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 的外借/阅览图书信息进行展示:

1      public class BookEditModel
2      {
3          public BookDetails BookDetails { get; set; }
4          public IEnumerable<Book> Books { get; set; }
5      }

 

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

 1         [Authorize(Roles = "Admin")]
 2         public IActionResult Books(string isbn)
 3         {
 4             BookEditModel model = new BookEditModel()
 5             {
 6                 Books = _context.Books.Where(b => b.ISBN == isbn),
 7                 BookDetails = _context.BooksDetail.FirstOrDefault(b => b.ISBN == isbn)
 8             };
 9             if (model.BookDetails==null)
10             {
11                 TempData["message"] = "未找到目标书籍";
12                 return RedirectToAction("BookDetails");                
13             }
14             return View(model);
15         }    

 

视图:

 1 @using LibraryDemo.Models.DomainModels
 2     @model BookEditModel
 3 
 4     @{
 5         ViewData["Title"] = "外借/阅览书籍信息";
 6         Book temp = new Book();
 7     }
 8 
 9 <script>
10     function confirmDelete() {
11         var barcodes = document.getElementsByName("barcodes");
12         var message="确认删除";
13         for (i in barcodes) {
14             if (barcodes[i].checked) {
15                 var book = barcodes[i].parentElement.nextElementSibling.firstElementChild.innerHTML;
16                 message=message+""+book+"";
17             }
18         }
19         message = message + "?";
20         if (confirm(message) == true) {
21             return true;
22         } else {
23             return false;
24         }
25     }
26 </script>
27 
28     <style type="text/css">
29         tr + tr {
30             border-top: thin solid gray;
31         }
32 
33         td + td {
34             padding-left: 100px;
35         }
36 
37         .container {
38             width: 1200px;
39         }
40     </style>
41 
42     <h2>《@Model.BookDetails.Name》</h2>
43     <br />
44 
45     @if (TempData["message"] != null)
46     {
47         <p style="font-size: large;color:red" >@TempData["message"]</p>
48         <br />
49         <br />
50     }
51 
52     <form asp-action="RemoveBooks" method="post">
53         <div>
54             <a class="btn btn-primary" asp-action="AddBook" asp-route-isbn="@Model.BookDetails.ISBN">添加外借书籍</a>
55             <button type="submit" class="btn btn-danger" onclick="return confirmDelete()"> 删除外借书籍</button>
56         </div>
57         <br />
58         <input type="hidden" name="isbn" value="@Model.BookDetails.ISBN"/>
59         <table>
60             <tbody>
61             <tr>
62                 <td></td>
63                 <td>@Html.LabelFor(b => temp.BarCode)</td>
64                 <td>@Html.LabelFor(b => temp.Bookshelf)</td>
65                 <td>@Html.LabelFor(b => temp.BorrowTime)</td>
66                 <td>@Html.LabelFor(b => temp.MatureTime)</td>
67                 <td>@Html.LabelFor(b => temp.AppointedLatestTime)</td>
68                 <td>@Html.LabelFor(b => temp.State)</td>
69                 <td>@Html.LabelFor(b => temp.Keeper)</td>
70             </tr>
71                 @if (Model.Books.ToList().Count == 0)
72                 {
73                     <tr><td colspan="7">未有《@Model.BookDetails.Name》的外借/阅览书籍信息</td></tr>
74                 }
75                 @foreach (var book in Model.Books)
76                 {
77                     <tr>
78                         <td><input type="checkbox" name="barcodes" value="@book.BarCode"/></td>
79                         <td><a asp-action="EditBook" asp-route-barcode="@book.BarCode">@Html.DisplayFor(b => book.BarCode)</a></td>
80                         <td>@Html.DisplayFor(b => book.BookshelfId)</td>
81                         <td>@Html.DisplayFor(b => book.BorrowTime)</td>
82                         <td>@Html.DisplayFor(b => book.MatureTime)</td>
83                         <td>@Html.DisplayFor(b => book.AppointedLatestTime)</td>
84                         <td>@Html.DisplayFor(b => book.State)</td>
85                         <td>@Html.DisplayFor(b => book.Keeper.Name)</td>
86                     </tr>
87                 }
88             </tbody>
89         </table>
90     </form>

 

 结果:

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

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

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

 

 

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

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

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

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

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

 1         [Authorize(Roles = "Admin")]
 2         public IActionResult AddBook(string isbn)
 3         {
 4             BookDetails bookDetails = _context.BooksDetail.FirstOrDefault(b => b.ISBN == isbn);
 5             if (bookDetails == null)
 6             {
 7                 return RedirectToAction("BookDetails", new { isbn = isbn });
 8             }
 9             Book book = new Book()
10             {
11                 ISBN = bookDetails.ISBN,
12                 Name = bookDetails.Name,
13                 FetchBookNumber = bookDetails.FetchBookNumber
14             };
15             return View(book);
16         }
17 
18         [HttpPost]
19         [ValidateAntiForgeryToken]
20         [Authorize(Roles = "Admin")]
21         public async Task<IActionResult> AddBook([Bind("ISBN,Name,FetchBookNumber,BarCode,BookshelfId,State")]Book book)
22         {
23             if (ModelState.IsValid)
24             {
25                 BookDetails bookDetails = _context.BooksDetail.FirstOrDefault(b => b.ISBN == book.ISBN);
26                 Book existBook = _context.Books.AsNoTracking().FirstOrDefault(b => b.BarCode == book.BarCode);
27                 if (existBook != null)
28                 {
29                     TempData["message"] = $"已有二维码为{book.BarCode}的书籍《{existBook.Name}》";
30                     return RedirectToAction("AddBook", new {isbn = book.ISBN});
31                 }
32                 if (bookDetails.Name == book.Name)
33                 {
34                     Bookshelf bookshelf = _context.Bookshelves.Include(b=>b.Books).FirstOrDefault(b => b.BookshelfId == book.BookshelfId);
35                     if (bookshelf != null)
36                     {
37                         book.Sort = bookshelf.Sort;
38                         book.Location = bookshelf.Location;
39                         bookshelf.Books.Add(book);
40                         bookshelf.MaxFetchNumber = bookshelf.Books.Max(b => b.FetchBookNumber);
41                         bookshelf.MinFetchNumber = bookshelf.Books.Min(b => b.FetchBookNumber);
42                     }
43                     await _context.Books.AddAsync(book);
44                     await _context.SaveChangesAsync();
45                     TempData["message"] = $"《{book.Name}》 {book.BarCode} 添加成功";
46                     return RedirectToAction("Books", new { isbn = book.ISBN });
47                 }
48             }
49             return View(book);
50         }    

 

 视图:

 1 @using LibraryDemo.Models.DomainModels
 2     @model LibraryDemo.Models.DomainModels.Book
 3 
 4     @{
 5         ViewData["Title"] = "AddBook";
 6     }
 7 
 8     <script>
 9         window.onload = function () {
10             $("input").addClass("form-control");
11         }
12         window.onbeforeunload = function () {
13             return "您的数据未保存,确定退出?";
14         }
15         function removeOnbeforeunload() {
16             window.onbeforeunload = "";
17         }
18     </script>
19 
20     <h2>@($"为《{Model.Name}》添加借阅/阅览书籍信息")</h2>
21     <br />
22     <br />
23     @if (TempData["message"] != null)
24     {
25         <p class="text-primary">@TempData["message"]</p>
26         <br />
27         <br />
28     }
29 
30     @Html.ValidationSummary(false, "", new { @class = "text-danger" })
31     <form asp-action="AddBook" method="post">
32         <div class="form-group">
33             @Html.LabelFor(b => b.ISBN)
34             <input type="text" value="@Model.ISBN" readonly="readonly" name="@nameof(Model.ISBN)" />
35         </div>
36         <div class="form-group">
37             @Html.LabelFor(b => b.Name)
38             <input type="text" value="@Model.Name" readonly="readonly" name="@nameof(Model.Name)" />
39         </div>
40         <div class="form-group">
41             @Html.LabelFor(b => b.FetchBookNumber)
42             <input type="text" value="@Model.FetchBookNumber" readonly="readonly" name="@nameof(Model.FetchBookNumber)" />
43         </div>
44         <div class="form-group">
45             @Html.LabelFor(b => Model.BarCode)
46             @Html.EditorFor(b => Model.BarCode)
47         </div>
48         <div class="form-group">
49             @Html.LabelFor(b => Model.BookshelfId)
50             @Html.EditorFor(b => Model.BookshelfId)
51         </div>
52         <div class="form-group">
53             @Html.LabelFor(b => Model.State)
54             @Html.DropDownListFor(b=>Model.State,Enum.GetValues(typeof(BookState)).Cast<Enum>().Select(state =>
55        {
56            string enumVal = Enum.GetName(typeof(BookState), state);
57            string displayVal;
58            switch (enumVal)
59            {
60                case "Normal":
61                    displayVal = "可借阅";
62                    break;
63                case "Readonly":
64                    displayVal = "馆内阅览";
65                    break;
66                case "Borrowed":
67                    displayVal = "已借出";
68                    break;
69                case "ReBorrowed":
70                    displayVal = "被续借";
71                    break;
72                case "Appointed":
73                    displayVal = "被预约";
74                    break;
75                default:
76                    displayVal = "";
77                    break;
78            }
79            return new SelectListItem()
80            {
81                Text=displayVal,
82                Value = enumVal
83            };
84        }))
85         </div>
86         <div class="form-group"></div>
87         <input type="submit" class="btn-success" onclick="removeOnbeforeunload()" />
88     </form>

 

 

 

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

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

 1         [Authorize(Roles = "Admin")]
 2         [HttpPost]
 3         [ValidateAntiForgeryToken]
 4         public async Task<IActionResult> RemoveBooks(IEnumerable<string> barcodes, string isbn)
 5         {
 6             StringBuilder sb = new StringBuilder();
 7             foreach (var barcode in barcodes)
 8             {
 9                 Book book = _context.Books.First(b => b.BarCode == barcode);
10                 _context.Books.Remove(book);
11                 sb.AppendLine($"{book.BarCode} 移除成功");
12             }
13             await _context.SaveChangesAsync();
14             TempData["message"] = sb.ToString();
15             return RedirectToAction("Books", new { isbn = isbn });
16         }    

 

 

四、增删总结果:

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

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

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

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

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

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

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

 

 

 

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

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

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

 1         [Authorize(Roles = "Admin")]
 2         public IActionResult EditBook(string barcode)
 3         {
 4             Book book = _context.Books.First(b => b.BarCode == barcode);
 5             return View(book);
 6         }
 7 
 8         [HttpPost]
 9         [Authorize(Roles = "Admin")]
10         [ValidateAntiForgeryToken]
11         public async Task<IActionResult> EditBook(string oldBarCode,[Bind("BarCode,BookshelfId,BorrowTime,Name,KeeperId,AppointedLatestTime")]Book book)
12         {
13             if (ModelState.IsValid)
14             {
15                 Book oldBook = _context.Books.FirstOrDefault(b => b.BarCode == oldBarCode);
16                 if (oldBook == null)
17                 {
18                     ViewBag["message"] = $"不存在二维码为{oldBarCode}的书籍";
19                     return RedirectToAction("BookDetails");
20                 }
21 
22                 if (oldBook.Name == book.Name)
23                 {
24                     book.ISBN = oldBook.ISBN;
25                     book.FetchBookNumber = oldBook.FetchBookNumber;
26                     Bookshelf bookshelf = _context.Bookshelves.Include(b => b.Books).FirstOrDefault(b => b.BookshelfId == book.BookshelfId);
27                     if (bookshelf != null)
28                     {                        
29                         book.Sort = bookshelf.Sort;
30                         book.Location = bookshelf.Location;
31                         bookshelf.Books.Remove(oldBook);
32                         bookshelf.Books.Add(book);
33                     }
34 
35                     _context.Books.Remove(oldBook);
36                     _context.Books.Add(book);
37                     await _context.SaveChangesAsync();
38                     TempData["message"] = "修改成功";
39                     return RedirectToAction("Books", new { isbn = oldBook.ISBN });
40                 }
41             }        
42             return View(book);
43         }

 

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

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

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