此教程在轻松愉快的氛围中介绍一个具有控制器和视图的 ASP.NET Core MVC Web 图书管理应用。
QQ群:577922290
对于初学者而言,在教程结束时,你将拥有一个管理和显示图书数据的简单应用,同时你还将会对自身的编程技术充满信心。
Visual Studio 2022下载安装操作不在本教程范围内,因为操作基本就是选择,然后下一步。如果安装失败,可自行百度!
下载地址:https://visualstudio.microsoft.com/zh-hans/free-developer-offers/
如果项目没有配置使用 SSL,Visual Studio 会弹出对话框:
同时我们也可以从“调试”菜单中以调试或非调试模式启动应用;
也可以通过选择工具栏中的“BookQuerySystem”按钮来调试应用;
下图是应用在Microsoft Edge浏览器上的运行效果!
在Microsoft Edge浏览器中按F12会调用开发者工具,单击左下方红框里的 切换仿真设备按钮 ,浏览器会模仿移动端网页尺寸。当窗口缩小到移动尺寸时,网页内容会智能调整显示位置,网页右上方红框位置会出现下拉框,我们通常称这种网页布局为响应式布局。
网页响应式布局归功于一个叫做Bootstrap的前端框架,如果你目前不懂什么是Bootstrap也没有关系,在以后的教程中我们会学到相关知识,你现在只要知道Bootstrap懂你就可以了!本教程的宗旨是用通俗易懂的语言让你站在整体的高度上来理解Asp.Net Core Mvc,而不是让你深陷于每一个细节的泥潭中!
也许这是你创建的第一个应用程序,虽然一行代码也没有输入,但还是要恭喜你,你成功了!多一些愉悦,少一些挫败感,快乐的编程!
上一章我已经创建了程序,但是程序中什么也没有,这并不是我们希望看到的。
图书数据是放在数据库中的,本章我们创建专门用来管理数据库中图书数据的类。这些类就是MVC中的Model部分。
首先创建一个叫Book的模型类,它定义了数据库中图书数据的属性。什么是图书数据的属性?比如说图书的Title、Id、price等都是图书属性。
右键单击 Models 文件夹,单击“添加” -> “类” 。 文件命名为Book.cs
namespace BookQuerySystem.Models
{
public class Book
{
public int Id { get; set; }
public string Title { get; set; }
public string ClassiFication { get; set; }
public string Author { get; set; }
[DataType(DataType.Date)]
public DateTime PublicationDate { get; set; }
public decimal price { get; set; }
}
}
Book 类包含一个 Id ,也是数据的主键。什么是数据的主键?简单理解就是唯一的编号,用来检索。
Book还包含这些属性:Title(书名)、ClassiFication(分类)、Author(作者)、PublicationDate(出版日期),Price(价格)。
PublicationDate上的DataType 特性声明了数据的类型 为Date。 那么特性又是什么东西?简单理解这里的特性就是在PublicationDate属性前面加一个 [ ] 方括号,然后把要给PublicationDate声明的信息放在方括号里。
现在我们收到了一个错误提示:
错误 CS0246 未能找到类型或命名空间名“DataTypeAttribute”(是否缺少 using 指令或程序集引用?) BookQuerySystem
解决这个错误的方法很简单,把鼠标放在红线上左键单击显示可能的修补程序。
左键单击using System.ComponentModel.DataAnnotations;
现在Book类的代码如下:
using System.ComponentModel.DataAnnotations;
namespace BookQuerySystem.Models
{
public class Book
{
public int Id { get; set; }
public string Title { get; set; }
public string ClassiFication { get; set; }
public string Author { get; set; }
[DataType(DataType.Date)]
public DateTime PublicationDate { get; set; }
public decimal Price { get; set; }
}
}
到这里,一个清晰明了的Book数据模型创建成功了,你通关了!恭喜你再一次站在了人生的巅峰!
上一章我们创建了一个Book数据模型类,通常我们称呼这个类为实体类。那么问题来了,这个实体类是做什么用的?你猜对了,当然是用来和数据库中的Book数据相互映射的。
映射: 在代数里,映射是个术语名词,指两个元素的集之间的元素相互“对应”的关系。
简单理解就是实体Book类和数据中的Book数据是一根绳上的蚂蚱!而Entity Framework Core 就是这根绳。
Entity Framework Core:轻量、可扩展、跨平台、开源的Entity Framework数据访问框架。
我们可以通过Entity Framework Core来连接数据库,并可以用Book实体类来处理数据库中的Book数据以实现底层数据的增、删、改、查。没错,藏在数据库中的数据我们称它为底层数据。
下面我们先安装Entity Framework Core:
Install-Package Microsoft.EntityFrameworkCore.Design
3.6164887秒之后,EF Core终于安装完毕。你用了多少秒,可以在下方留言告诉我,看看谁用时最短!
别怕,你电脑没死机!休息,休息一会儿!
事实证明基架就是打工人,我们才是老板!一番等待之后,基架为我们干了很多活:
我们之前谈过基架的职能,目前只要知道基架更新了什么就可以,至于它是怎么更新的并不重要。
基架还为我们创建了以下内容:
“创建(Create)”、“删除(Delete)”、“详细信息(Details)”、“编辑(Edit)”和“索引(Index)”的Razor视图文件:Views/Books/*.cshtml
数据库上下文类:Data/BookQuerySystemContext.cs)”
目前只要知道基架创建了什么就可以,不要强迫自己把每一个细节搞清楚,要站在全局的高度看问题,细节就先留给基架吧。
实体类的工作已经做完,现在我们使用EF Core的迁移功能来创建数据库。
迁移:是一组创建和更新数据库以匹配实体类的工具。
迁移功能的用法也非常简单:
Add-Migration InitialCreate
InitialCreate单词的翻译是初始创建,未必非要用这个词,你也可以自行命名。
现在项目中多出了一个Migrations文件夹,里面的{timestamp}_InitialCreate.cs 迁移文件包含了创建书库的代码,timestamp根据时间不同而定,我的就是20211206090830_InitialCreate.cs。
现在用于创建数据库的代码已经存在,我们用Update-Database命令来真正的创建数据库。
Update-Database
Update-Database:将数据库更新到上一个最近创建的迁移,我们上一个迁移是20211206090830_InitialCreate.cs,现在数据库和它保持同步了。Update-Database命令本质就是运行了一下20211206090830_InitialCreate.cs中的Up方法,一点都不神秘。
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace BookQuerySystem.Migrations
{
public partial class InitialCreate : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Book",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
Title = table.Column<string>(type: "nvarchar(max)", nullable: false),
ClassiFication = table.Column<string>(type: "nvarchar(max)", nullable: false),
Author = table.Column<string>(type: "nvarchar(max)", nullable: false),
PublicationDate = table.Column<DateTime>(type: "datetime2", nullable: false),
Price = table.Column<decimal>(type: "decimal(18,2)", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Book", x => x.Id);
});
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Book");
}
}
}
凭借阅读英文,大家也能猜出Up方法大概都做了什么。这个也不重要,我们知道有这么一回事就行了,不用深究。
小伙伴们,下面是见证奇迹的时刻,让我们把应用运行起来吧!老规矩,按Ctrl+F5 在非调试情况下启动应用。
惊不惊喜?意不意外?(可以留言告诉我!)
第一章啥样,现在还啥样!网页一点变化也没有。为什么会这样?
一个 HTTP 终点是 Web 应用程序中的Url目标,如 https://localhost:7260/Books ,Books就是目标。
https://localhost:{PORT}/Books ,将 {PORT} 替换为你自己的端口号。看不明白就在刚才你打开的网页网址后加上/Books就行了。
打开https://localhost:7260/Books后才会看我们的劳动成果!
现在我们试试创建图书功能,左键单击网页中的Create New。在创建页面填写书籍信息后点击Create提交创建信息:
现在Books页面显示了新添加书籍的信息。
在Price(Price)26.6之后,我们看到了Edit(编辑)、Detail(查看详情)和Delete(删除)选项,请自行测试一遍。
一本书看起来很孤独,我们再自行添加几本书。
页面现在看起来顺眼多了,但是如何才能把英语换成汉语那?
打开Models文件夹下的Books.cs实体类:
在除了Id属性之外的属性上添加[Display(Name=" 中文")],我们之前讲过,这种写法叫做给属性添加特性。
using System.ComponentModel.DataAnnotations;
namespace BookQuerySystem.Models
{
public class Book
{
public int Id { get; set; }
[Display(Name ="书名")]
public string Title { get; set; }
[Display(Name ="类型")]
public string ClassiFication { get; set; }
[Display(Name ="作者")]
public string Author { get; set; }
[Display(Name ="首版日期")]
[DataType(DataType.Date)]
public DateTime PublicationDate { get; set; }
[Display(Name ="价格")]
public decimal Price { get; set; }
}
}
重新启动应用:
添加特性的Book实体类各个属性都以中文方式显示在了页面上。从字面上我们也能理解Display是显示的意思。[Display(Name=" “)]就是把他修饰的元素名显示为” “里的内容,比如说[Display(Name=” 价格")]。
把Edit、Details、Delete也改成汉语:
打开Views/Books/Index.cshtml文件
@model IEnumerable<BookQuerySystem.Models.Book>
@{
ViewData["Title"] = "Index";
}
<h1>Indexh1>
<p>
<a asp-action="Create">Create Newa>
p>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.Title)
th>
<th>
@Html.DisplayNameFor(model => model.ClassiFication)
th>
<th>
@Html.DisplayNameFor(model => model.Author)
th>
<th>
@Html.DisplayNameFor(model => model.PublicationDate)
th>
<th>
@Html.DisplayNameFor(model => model.Price)
th>
<th>th>
tr>
thead>
<tbody>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Title)
td>
<td>
@Html.DisplayFor(modelItem => item.ClassiFication)
td>
<td>
@Html.DisplayFor(modelItem => item.Author)
td>
<td>
@Html.DisplayFor(modelItem => item.PublicationDate)
td>
<td>
@Html.DisplayFor(modelItem => item.Price)
td>
<td>
<a asp-action="Edit" asp-route-id="@item.Id">Edita> |
<a asp-action="Details" asp-route-id="@item.Id">Detailsa> |
<a asp-action="Delete" asp-route-id="@item.Id">Deletea>
td>
tr>
}
tbody>
table>
Index.cshtml最后几行找到代码
修改如下:
左键点击热重载:
刷新浏览器:
还是Views/Books/Index.cshtm文件,在上面找到
修改代码:
热重载:
修改之后网页终于大部分显示的都是汉语了,不过细心的小伙伴会发现页面中竟然还有英语。之前修改的是Views/Books/Index.cshtm文件中的内容,在Program.cs文件中路由格式如下:
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
这是一种路由格式,controller就是控制器,action指明控制器中的方法,在本例中id就是图书Id编号。id后面加一个?号表示这个id可空,可空就是在路由过程中可以写,也可以省略。
https://localhost:7260/Books是一个Url,也就是网址,当访问这个网址时,我们实际访问的是https://localhost:7260/Books/Index页面,Books是控制器,Index是Books控制器中的方法,/Books=/Books/Index就是Program.cs文件中路由定义好的默认规则。如果直接启动应用,Url将默认是https://localhost:7260/ , /=/Home/Index 是默认路由。(以上路由知识如果没看懂则可以直接无视,这并不影响应用运行)
打开Views/Shared/_layout.cshtml文件,代码修改如下:
DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - 图书查询系统title>
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
<link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
<link rel="stylesheet" href="~/BookQuerySystem.styles.css" asp-append-version="true" />
head>
<body>
<header>
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
<div class="container-fluid">
<a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">图书查询系统a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbarSupportedContent"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon">span>
button>
<div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
<ul class="navbar-nav flex-grow-1">
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">首页a>
li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Books" asp-action="Index">图书列表a>
li>
ul>
div>
div>
nav>
header>
<div class="container">
<main role="main" class="pb-3">
@RenderBody()
main>
div>
<footer class="border-top footer text-muted">
<div class="container">
© 2021 - 图书查询系统 - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacya>
div>
footer>
<script src="~/lib/jquery/dist/jquery.min.js">script>
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js">script>
<script src="~/js/site.js" asp-append-version="true">script>
@await RenderSectionAsync("Scripts", required: false)
body>
html>
这是布局页面,把其它网页中重复出现的共用内容写在布局页里。日后维护时修改共用内容只需修改这一页即可!其他页面内容都在@RenderBody()位置呈现,除此之外都是各页面的共用内容。依照下图修改红框中内容:
热重载:
修改Views/Books/Create.cshtml文件:
修改后代码:
@model BookQuerySystem.Models.Book
@{
ViewData["Title"] = "录入图书";
}
<h1>图书录入h1>
<h4>图书h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger">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">
<label asp-for="ClassiFication" class="control-label">label>
<input asp-for="ClassiFication" class="form-control" />
<span asp-validation-for="ClassiFication" class="text-danger">span>
div>
<div class="form-group">
<label asp-for="Author" class="control-label">label>
<input asp-for="Author" class="form-control" />
<span asp-validation-for="Author" class="text-danger">span>
div>
<div class="form-group">
<label asp-for="PublicationDate" class="control-label">label>
<input asp-for="PublicationDate" class="form-control" />
<span asp-validation-for="PublicationDate" class="text-danger">span>
div>
<div class="form-group">
<label asp-for="Price" class="control-label">label>
<input asp-for="Price" class="form-control" />
<span asp-validation-for="Price" class="text-danger">span>
div>
<div class="form-group">
<input type="submit" value="创建" class="btn btn-primary" />
div>
form>
div>
div>
<div>
<a asp-action="Index">返回图书列表a>
div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
Views/Books/Delete.cshtml文件修改后代码:
@model BookQuerySystem.Models.Book
@{
ViewData["Title"] = "删除";
}
<h1>删除h1>
<h3>你确定要删除这本书?h3>
<div>
<h4>图书h4>
<hr />
<dl class="row">
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.Title)
dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.Title)
dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.ClassiFication)
dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.ClassiFication)
dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.Author)
dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.Author)
dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.PublicationDate)
dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.PublicationDate)
dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.Price)
dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.Price)
dd>
dl>
<form asp-action="Delete">
<input type="hidden" asp-for="Id" />
<input type="submit" value="删除" class="btn btn-danger" /> |
<a asp-action="Index">返回a>
form>
div>
Views/Books/Details.cshtml文件修改后代码:
@model BookQuerySystem.Models.Book
@{
ViewData["Title"] = "详情";
}
<h1>详情h1>
<div>
<h4>图书h4>
<hr />
<dl class="row">
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.Title)
dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.Title)
dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.ClassiFication)
dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.ClassiFication)
dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.Author)
dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.Author)
dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.PublicationDate)
dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.PublicationDate)
dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.Price)
dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.Price)
dd>
dl>
div>
<div>
<a asp-action="Edit" asp-route-id="@Model.Id">编辑a> |
<a asp-action="Index">返回a>
div>
Views/Books/Edit.cshtml文件修改后代码:
@model BookQuerySystem.Models.Book
@{
ViewData["Title"] = "编辑";
}
<h1>编辑h1>
<h4>图书h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Edit">
<div asp-validation-summary="ModelOnly" class="text-danger">div>
<input type="hidden" asp-for="Id" />
<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">
<label asp-for="ClassiFication" class="control-label">label>
<input asp-for="ClassiFication" class="form-control" />
<span asp-validation-for="ClassiFication" class="text-danger">span>
div>
<div class="form-group">
<label asp-for="Author" class="control-label">label>
<input asp-for="Author" class="form-control" />
<span asp-validation-for="Author" class="text-danger">span>
div>
<div class="form-group">
<label asp-for="PublicationDate" class="control-label">label>
<input asp-for="PublicationDate" class="form-control" />
<span asp-validation-for="PublicationDate" class="text-danger">span>
div>
<div class="form-group">
<label asp-for="Price" class="control-label">label>
<input asp-for="Price" class="form-control" />
<span asp-validation-for="Price" class="text-danger">span>
div>
<div class="form-group">
<input type="submit" value="保存" class="btn btn-primary" />
div>
form>
div>
div>
<div>
<a asp-action="Index">返回a>
div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
现在我们修改欢迎页面Views/Home/Index.cshtml :
@{
ViewData["Title"] = "主页";
}
<div class="text-center">
<h1 class="display-4">你好!h1>
<p> <a href="https://blog.csdn.net/baidu_38495508/article/details/121731637">欢迎学习图书查询系统教程a>p>
div>
试想一下,如果数据库中存储着一万本书,你要找到其中一本书的数据,一条一条的翻找信息既费时又费力。既然是图书查询系统,那么应该有查询功能。
public async Task<IActionResult> Index(string search)
{
var books = from b in _context.Book
select b;
if (!string.IsNullOrEmpty(search))
{
books = books.Where(s=>s.Title!.Contains(search));
}
return View(await books.ToListAsync());
}
@model IEnumerable<BookQuerySystem.Models.Book>
@{
ViewData["Title"] = "图书列表";
}
<h1>图书列表h1>
<p>
<a asp-action="Create">录入图书a>
p>
<form asp-controller="Books" asp-action="Index">
<p>
书名: <input type="text" name="search" />
<input type="submit" value="搜索" />
p>
form>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.Title)
th>
<th>
@Html.DisplayNameFor(model => model.ClassiFication)
th>
<th>
@Html.DisplayNameFor(model => model.Author)
th>
<th>
@Html.DisplayNameFor(model => model.PublicationDate)
th>
<th>
@Html.DisplayNameFor(model => model.Price)
th>
<th>th>
tr>
thead>
<tbody>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Title)
td>
<td>
@Html.DisplayFor(modelItem => item.ClassiFication)
td>
<td>
@Html.DisplayFor(modelItem => item.Author)
td>
<td>
@Html.DisplayFor(modelItem => item.PublicationDate)
td>
<td>
@Html.DisplayFor(modelItem => item.Price)
td>
<td>
<a asp-action="Edit" asp-route-id="@item.Id">编辑a> |
<a asp-action="Details" asp-route-id="@item.Id">详情a> |
<a asp-action="Delete" asp-route-id="@item.Id">删除a>
td>
tr>
}
tbody>
table>
热重载:
在搜索框中输入“老人”。
左键单击“搜索”。
系统通过输入内容为我们搜索并匹配到了老人与海这本书。如果我们想通过书的类型搜索数据又应该怎么做那?
右键单击解决方案资源管理器中的BookQuerySystem->添加->新建文件夹,文件夹命名为ViewModels。
创建新类文件ViewModels/BookClassiFicationViewModel.cs ,类名有点长!好在易懂。
namespace BookQuerySystem.ViewModels
{
public class BookClassiFicationViewModel
{
public List<Book>? Books { get; set; }
public SelectList? ClassiFications { get; set; }
public string? BookClassiFication { get; set; }
public string? Search { get; set; }
}
}
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using BookQuerySystem.Data;
using BookQuerySystem.Models;
using BookQuerySystem.ViewModels;
namespace BookQuerySystem.Controllers
{
public class BooksController : Controller
{
private readonly BookQuerySystemContext _context;
public BooksController(BookQuerySystemContext context)
{
_context = context;
}
// GET: Books
public async Task<IActionResult> Index(string bookClassiFication , string search)
{
IQueryable<string> classiFicationQuery = from c in _context.Book
orderby c.ClassiFication
select c.ClassiFication;
var books = from b in _context.Book
select b;
if (!string.IsNullOrEmpty(search))
{
books = books.Where(s=>s.Title!.Contains(search));
}
if (!string.IsNullOrEmpty(bookClassiFication))
{
books = books.Where(b=>b.ClassiFication==bookClassiFication);
}
var bookClassiFicationVM = new BookClassiFicationViewModel
{
ClassiFications = new SelectList(await classiFicationQuery.Distinct().ToListAsync()),
Books = await books.ToListAsync()
};
return View(bookClassiFicationVM);
}
// GET: Books/Details/5
public async Task<IActionResult> Details(int? id)
{
if (id == null)
{
return NotFound();
}
var book = await _context.Book
.FirstOrDefaultAsync(m => m.Id == id);
if (book == null)
{
return NotFound();
}
return View(book);
}
// GET: Books/Create
public IActionResult Create()
{
return View();
}
// POST: Books/Create
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Id,Title,ClassiFication,Author,PublicationDate,Price")] Book book)
{
if (ModelState.IsValid)
{
_context.Add(book);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(book);
}
// GET: Books/Edit/5
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var book = await _context.Book.FindAsync(id);
if (book == null)
{
return NotFound();
}
return View(book);
}
// POST: Books/Edit/5
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("Id,Title,ClassiFication,Author,PublicationDate,Price")] Book book)
{
if (id != book.Id)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
_context.Update(book);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!BookExists(book.Id))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction(nameof(Index));
}
return View(book);
}
// GET: Books/Delete/5
public async Task<IActionResult> Delete(int? id)
{
if (id == null)
{
return NotFound();
}
var book = await _context.Book
.FirstOrDefaultAsync(m => m.Id == id);
if (book == null)
{
return NotFound();
}
return View(book);
}
// POST: Books/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DeleteConfirmed(int id)
{
var book = await _context.Book.FindAsync(id);
_context.Book.Remove(book);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
private bool BookExists(int id)
{
return _context.Book.Any(e => e.Id == id);
}
}
}
@model BookQuerySystem.ViewModels.BookClassiFicationViewModel
@{
ViewData["Title"] = "图书列表";
}
<h1>图书列表h1>
<p>
<a asp-action="Create">录入图书a>
p>
<form asp-controller="Books" asp-action="Index" method="get">
<p>
<select asp-for="BookClassiFication" asp-items="Model.ClassiFications">
<option value="">所有类别option>
select>
书名: <input type="text" name="Search" />
<input type="submit" value="搜索" />
p>
form>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.Books[0].Title)
th>
<th>
@Html.DisplayNameFor(model => model.Books[0].ClassiFication)
th>
<th>
@Html.DisplayNameFor(model => model.Books[0].Author)
th>
<th>
@Html.DisplayNameFor(model => model.Books[0].PublicationDate)
th>
<th>
@Html.DisplayNameFor(model => model.Books[0].Price)
th>
<th>th>
tr>
thead>
<tbody>
@foreach (var item in Model.Books) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Title)
td>
<td>
@Html.DisplayFor(modelItem => item.ClassiFication)
td>
<td>
@Html.DisplayFor(modelItem => item.Author)
td>
<td>
@Html.DisplayFor(modelItem => item.PublicationDate)
td>
<td>
@Html.DisplayFor(modelItem => item.Price)
td>
<td>
<a asp-action="Edit" asp-route-id="@item.Id">编辑a> |
<a asp-action="Details" asp-route-id="@item.Id">详情a> |
<a asp-action="Delete" asp-route-id="@item.Id">删除a>
td>
tr>
}
tbody>
table>
热重载:
入门教程到这里就结束了,编程是不是很简单,很快乐?
教程最后还会提供加上会员管理系统的代码码,使项目功能完整。小伙伴们可以下载源码自行修改。
效果还行 ,在没有注册登录之前只可以浏览注册和登录页面,现在非用户已经无法看到你书库的图书信息了。
角色已经添加完毕,效果如下:
小伙伴们可以下载代码自行阅读,修改,使用。
代码在 QQ群:577922290 群文件中共享。