zoukankan      html  css  js  c++  java
  • ASP.NET Core MVC 打造一个简单的图书馆管理系统 (修正版)(五)外借/阅览图书信息的增删改查

    前言:

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

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

    微软文档: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              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>

     

  • 相关阅读:
    技术文章阅读-Pi-Hole < 4.3.2 Command Injection & PrivEsc (CVE-2019-13051)
    技术文章阅读-d-link-routers-found-vulnerable-rce
    技术文章阅读-蜂网互联企业级路由器v4.31密码泄露漏洞
    使用mkcert工具自签https证书
    查询给定时间是否在当前周
    nodeJS 一些笔记
    手机端页面布局方案
    关于HTML5的应用缓存功能
    将伪数组转换为数组的方法
    Cookies的使用之购物车的实现
  • 原文地址:https://www.cnblogs.com/gokoururi/p/10386531.html
Copyright © 2011-2022 走看看