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

前言:

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

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

微软文档: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 BookListViewModel
2     {
3         public IEnumerable<BookDetails> BookDetails { get; set; }
4         public PagingInfo PagingInfo { get; set; }
5     }

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

 1         [Authorize(Roles = "Admin")]
 2         public IActionResult Books(string isbn)
 3         {
 4             BookEditModel model = new BookEditModel()
 5             {
 6                 Books = _lendingInfoDbContext.Books.Include(b => b.Keeper).AsNoTracking().Where(b => b.ISBN == isbn),
 7                 BookDetails = _lendingInfoDbContext.BooksDetail.AsNoTracking().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: 50px;
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.KeeperId)</td>
70                 <td>编辑借出信息</td>
71             </tr>
72                 @if (Model.Books.ToList().Count == 0)
73                 {
74                     <tr><td colspan="7">未有《@Model.BookDetails.Name》的外借/阅览书籍信息</td></tr>
75                 }
76                 @foreach (var book in Model.Books)
77                 {
78                     <tr>
79                         <td><input type="checkbox" name="barcodes" value="@book.BarCode"/></td>
80                         <td><a asp-action="EditBook" asp-route-barcode="@book.BarCode">@Html.DisplayFor(b => book.BarCode)</a></td>
81                         <td>@Html.DisplayFor(b => book.BookshelfId)</td>
82                         <td>@Html.DisplayFor(b => book.BorrowTime)</td>
83                         <td>@Html.DisplayFor(b => book.MatureTime)</td>
84                         <td>@Html.DisplayFor(b => book.AppointedLatestTime)</td>
85                         <td>@Html.DisplayFor(b => book.State)</td>
86                         <td>@Html.DisplayFor(b => book.Keeper.Name)</td>
87                         <td><a asp-action="EditLendingInfo" asp-route-barcode="@book.BarCode">编辑</a></td>
88                     </tr>
89                 }
90             </tbody>
91         </table>
92     </form>

 结果:

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

在 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 = _lendingInfoDbContext.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 = _lendingInfoDbContext.BooksDetail.FirstOrDefault(b => b.ISBN == book.ISBN);
26                 Book existBook = _lendingInfoDbContext.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 = _lendingInfoDbContext.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 _lendingInfoDbContext.Books.AddAsync(book);
44                     await _lendingInfoDbContext.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-success">@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 = _lendingInfoDbContext.Books.First(b => b.BarCode == barcode);
10                 _lendingInfoDbContext.Books.Remove(book);
11                 sb.AppendLine($"{book.BarCode} 移除成功");
12             }
13             await _lendingInfoDbContext.SaveChangesAsync();
14             TempData["message"] = sb.ToString();
15             return RedirectToAction("Books", new { isbn = isbn });
16         }

四、增删总结果:

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

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

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

 1         [Authorize(Roles = "Admin")]
 2         public IActionResult EditBook(string barcode)
 3         {
 4             Book book = _lendingInfoDbContext.Books.FirstOrDefault(b => b.BarCode == barcode);
 5             if (book == null)
 6             {
 7                 return RedirectToAction("BookDetails");
 8             }
 9             return View(book);
10         }
11 
12         [HttpPost]
13         [Authorize(Roles = "Admin")]
14         [ValidateAntiForgeryToken]
15         public async Task<IActionResult> EditBook(string oldBarCode, [Bind("BarCode,BookshelfId,Name,State")]Book book)
16         {
17             if (ModelState.IsValid)
18             {
19                 Book oldBook = _lendingInfoDbContext.Books.FirstOrDefault(b => b.BarCode == oldBarCode);
20                 if (oldBook == null)
21                 {
22                     TempData["message"] = $"不存在二维码为{oldBarCode}的书籍";
23                     return RedirectToAction("BookDetails");
24                 }
25 
26                 if (oldBook.Name == book.Name)
27                 {
28                     book.ISBN = oldBook.ISBN;
29                     book.FetchBookNumber = oldBook.FetchBookNumber;
30                     Bookshelf bookshelf = _lendingInfoDbContext.Bookshelves.Include(b => b.Books).FirstOrDefault(b => b.BookshelfId == book.BookshelfId);
31                     if (bookshelf != null)
32                     {
33                         book.Sort = bookshelf.Sort;
34                         book.Location = bookshelf.Location;
35                         bookshelf.Books.Remove(oldBook);
36                         bookshelf.Books.Add(book);
37                     }
38 
39                     _lendingInfoDbContext.Books.Remove(oldBook);
40                     _lendingInfoDbContext.Books.Add(book);
41                     await _lendingInfoDbContext.SaveChangesAsync();
42                     TempData["message"] = "修改成功";
43                     return RedirectToAction("Books", new { isbn = oldBook.ISBN });
44                 }
45             }
46             return View(book);
47         }
 1 @using LibraryDemo.Models.DomainModels
 2 @model LibraryDemo.Models.DomainModels.Book
 3 
 4 @{
 5     ViewData["Title"] = "EditBook";
 6 }
 7 
 8 <script>
 9     window.onload = function () {
10         $("input").addClass("form-control");
11     }
12     window.onbeforeunload = function (event) {
13         return "您的数据未保存,确定退出?";
14     }
15     function removeOnbeforeunload() {
16         window.onbeforeunload = "";
17     }
18 </script>
19 
20 <h2>编辑外借书籍</h2>
21 <br />
22 <h3>《@Model.Name》</h3>
23 <br />
24 <h4>原二维码:@Model.BarCode</h4>
25 <br />
26 @Html.ValidationSummary(false,"",new{@class="text-danger"})
27 
28 <form asp-action="EditBook" method="post">
29     <input type="hidden" name="oldBarCode" value="@Model.BarCode" />
30     <input type="hidden" name="Name" value="@Model.Name" />
31     <div class="form-group">
32         @Html.LabelFor(b => b.BarCode)
33         @Html.EditorFor(b => b.BarCode)
34     </div>
35     <div class="form-group">
36         @Html.LabelFor(b => b.BookshelfId)
37         @Html.EditorFor(b => b.BookshelfId)
38     </div>
39     <div class="form-group">
40         @Html.LabelFor(b => b.State)
41         @Html.DropDownListFor(b => b.State, Enum.GetValues(typeof(BookState)).Cast<Enum>().Select(state =>
42         {
43             string enumVal = Enum.GetName(typeof(BookState), state);
44             string displayVal;
45             switch (enumVal)
46             {
47                 case "Normal":
48                     displayVal = "可借阅";
49                     break;
50                 case "Readonly":
51                     displayVal = "馆内阅览";
52                     break;
53                 case "Borrowed":
54                     displayVal = "已借出";
55                     break;
56                 case "ReBorrowed":
57                     displayVal = "被续借";
58                     break;
59                 case "Appointed":
60                     displayVal = "被预约";
61                     break;
62                 default:
63                     displayVal = "";
64                     break;
65             }
66             return new SelectListItem()
67             {
68                 Text = displayVal,
69                 Value = enumVal,
70                 Selected = Model.State.ToString() == enumVal
71             };
72         }))
73     </div>
74     <div class="form-group"></div>
75     <input type="submit" class="btn-success" onclick="removeOnbeforeunload()" />
76 </form>

 

猜你喜欢

转载自www.cnblogs.com/gokoururi/p/10386531.html