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
本章内容:对图书馆系统组成的简要分析。以及对域模型以及相应数据库的建立。
知识点:Code First、EF 基本使用方法、ASP.NET Core 使用 EF Core 的配置方法、EF 多对多关系的建立。
一、对图书馆系统域模型的分析
一个图书馆系统需要有管理员、 学生、书架以及书籍
域模型,即用来存储数据的模型。
在此域模型可以用以下结构创建:
二、项目结构
然后就可以开始建立该项目了:
三、建立域模型
学位枚举:
public enum Degrees { [Display(Name = "本科生")] CollegeStudent, [Display(Name = "研究生")] Postgraduate, [Display(Name = "博士生")] DoctorateDegree }
图书借阅状态枚举:
public enum BookState { /// <summary> /// 可借阅 /// </summary> [Display(Name = "正常")] Normal, /// <summary> /// 馆内阅览 /// </summary> [Display(Name = "馆内阅览")] Readonly, /// <summary> /// 已借出 /// </summary> [Display(Name = "已借出")] Borrowed, /// <summary> /// 被续借 /// </summary> [Display(Name = "被续借")] ReBorrowed, /// <summary> /// 被预约 /// </summary> [Display(Name = "被预约")] Appointed, [Display(Name = "过期")] Expired }
该项目准备使用一个数据库存储学生账户信息,另一个则用于存储学生借书信息:
学生账户信息:
public class Student : IdentityUser { /// <summary> /// 学号 /// </summary> [ProtectedPersonalData] [RegularExpression("[UIA]\\d{9}")] [Display(Name = "学号")] public override string UserName { get; set; } [Display(Name = "手机号")] [StringLength(14, MinimumLength = 11)] public override string PhoneNumber { get; set; } [Display(Name = "姓名")] public string Name { get; set; } [Display(Name = "学历")] public Degrees Degree { get; set; } [Display(Name = "最大借书数目")] public int MaxBooksNumber { get; set; } }
书籍信息:
public class Book { /// <summary> /// 二维码 /// </summary> [Key] [Display(Name = "二维码")] [Required(ErrorMessage = "未填写二维码")] public string BarCode { get; set; } public string ISBN { get; set; } /// <summary> /// 书名 /// </summary> [Display(Name = "书名")] public string Name { get; set; } /// <summary> /// 取书号 /// </summary> [Display(Name = "取书号")] public string FetchBookNumber { get; set; } /// <summary> /// 所在书架 /// </summary> public Bookshelf Bookshelf { get; set; } [Display(Name = "书架号")] public int BookshelfId { get; set; } /// <summary> /// 借出时间 /// </summary> [Display(Name = "借出时间")] public DateTime? BorrowTime { get; set; } /// <summary> /// 到期时间 /// </summary> [Display(Name = "到期时间")] public DateTime? MatureTime { get; set; } /// <summary> /// 预约最晚借书日期 /// </summary> [Display(Name = "预约取书时间")] public DateTime? AppointedLatestTime { get; set; } /// <summary> /// 借阅状态 /// </summary> [Display(Name = "书籍状态")] public BookState State { get; set; } /// <summary> /// 持有者,指定外键 /// </summary> public StudentInfo Keeper { get; set; } [Display(Name = "持有者学号")] public string KeeperId{ get; set; } [Display(Name = "位置")] public string Location { get; set; } [Display(Name = "分类")] public string Sort { get; set; } public ICollection<AppointmentOrLending> Appointments { get; set; } }
书架信息:
public class Bookshelf { /// <summary> /// 书架ID /// </summary> [Key] //不自动增长 [DatabaseGenerated(DatabaseGeneratedOption.None)] public int BookshelfId { get; set; } /// <summary> /// 书架的书籍类别 /// </summary> [Required] public string Sort { get; set; } /// <summary> /// 最小取书号 /// </summary> [Required] public string MinFetchNumber { get; set; } [Required] public string MaxFetchNumber { get; set; } /// <summary> /// 书架位置 /// </summary> [Required] public string Location { get; set; } /// <summary> /// 全部藏书 /// </summary> public ICollection<Book> Books { get; set; } }
由于一个学生可以借阅多本书籍,一本书籍可被多人预约,因此书籍和学生具有多对多的关系,在此引入中间类:
其中的 AppointingDateTime 用来区分中间类包含的书籍是借阅书籍还是预约书籍:
public class AppointmentOrLending { public Book Book { get; set; } public string BookId { get; set; } public StudentInfo Student { get; set; } public string StudentId { get; set; } public DateTime? AppointingDateTime { get; set; } }
学生借书信息:
在 EF 中多对多关系实际上是两个多对一关系。此处 ICollection 的属性成为导航属性,用来提示 EF StudentInfo 和 AppointmentOrLending 之间存在着多对一的关系。
public class StudentInfo { [Key] public string UserName { get; set; } [Required] public string Name { get; set; } /// <summary> /// 学位,用来限制借书数目 /// </summary> [Required] public Degrees Degree { get; set; } /// <summary> /// 最大借书数目 /// </summary> [Required] public int MaxBooksNumber { get; set; } /// <summary> /// 已借图书 /// </summary> public ICollection<AppointmentOrLending> KeepingBooks { get; set; } public string AppointingBookBarCode { get; set; } [StringLength(14, MinimumLength = 11)] public string PhoneNumber { get; set; } /// <summary> /// 罚款 /// </summary> public decimal Fine { get; set; } }
外借/阅览书籍信息:
在约定中,若不指定主键,则 EF 会使用 (类名)+ID 的方式指定或创建主键,在此使用 [Key] 指定主键,使用 [Required] 指定字段为必须,这种可以为属性添加在数据库中的约束或者在视图中的约束的修饰称为 DataAnnotations 。
此处 ICollection 的属性成为导航属性,用来提示 EF Book 和 AppointmentOrLending 之间存在着多对一的关系。
public class Book { /// <summary> /// 二维码 /// </summary> [Key] [Display(Name = "二维码")] [Required(ErrorMessage = "未填写二维码")] public string BarCode { get; set; } public string ISBN { get; set; } /// <summary> /// 书名 /// </summary> [Display(Name = "书名")] public string Name { get; set; } /// <summary> /// 取书号 /// </summary> [Display(Name = "取书号")] public string FetchBookNumber { get; set; } /// <summary> /// 所在书架 /// </summary> public Bookshelf Bookshelf { get; set; } [Display(Name = "书架号")] public int BookshelfId { get; set; } /// <summary> /// 借出时间 /// </summary> [Display(Name = "借出时间")] public DateTime? BorrowTime { get; set; } /// <summary> /// 到期时间 /// </summary> [Display(Name = "到期时间")] public DateTime? MatureTime { get; set; } /// <summary> /// 预约最晚借书日期 /// </summary> [Display(Name = "预约取书时间")] public DateTime? AppointedLatestTime { get; set; } /// <summary> /// 借阅状态 /// </summary> [Display(Name = "书籍状态")] public BookState State { get; set; } /// <summary> /// 持有者,指定外键 /// </summary> public StudentInfo Keeper { get; set; } [Display(Name = "持有者学号")] public string KeeperId{ get; set; } [Display(Name = "位置")] public string Location { get; set; } [Display(Name = "分类")] public string Sort { get; set; } public ICollection<AppointmentOrLending> Appointments { get; set; } }
四、创建 DbContext
学生账户信息数据库:
public class StudentIdentityDbContext:IdentityDbContext<Student> { public StudentIdentityDbContext(DbContextOptions<StudentIdentityDbContext> options) : base(options) { } }
借阅信息数据库:
为了使 StudentInfo 类的 UserName 和 Book 的 BarCode 共同作为 AppointmentOrLending 中间类的主键,需覆写 OnModelCreating 方法:
至此 StudentInfo 和 Book 的多对多关系正式确立。
public class LendingInfoDbContext:DbContext { public LendingInfoDbContext(DbContextOptions<LendingInfoDbContext> options) : base(options) { } public DbSet<Book> Books { get; set; } public DbSet<BookDetails> BooksDetail { get; set; } public DbSet<Bookshelf> Bookshelves { get; set; } public DbSet<RecommendedBook> RecommendedBooks { get; set; } public DbSet<StudentInfo> Students { get; set; } public DbSet<AppointmentOrLending> AppointmentOrLendings { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.Entity<AppointmentOrLending>() .HasKey(c => new { c.BookId, c.StudentId }); } }
于是 Book 和 StudentInfo 之间的多对多关系确立完成。
五、根据约定配置数据库,进行依赖注入
在 appsettings.json 中添加数据库连接字符串。
{ "ConnectionStrings": { "LendingInfoDbContext": "Server=(localdb)\\mssqllocaldb;Database=LendingInfoDbContext;Trusted_Connection=True;MultipleActiveResultSets=true", "StudentIdentityDbContext": "Server=(localdb)\\mssqllocaldb;Database=StudentIdentityDbContext;Trusted_Connection=True;MultipleActiveResultSets=true" }, "Logging": { "LogLevel": { "Default": "Warning" } }, "AllowedHosts": "*" }
在 Startup.cs 中的 ConfigureServices 方法中对数据库进行配置:
services.AddDbContext<LendingInfoDbContext>(options => { options.UseSqlServer(Configuration.GetConnectionString("LendingInfoDbContext")); }); services.AddDbContext<StudentIdentityDbContext>(options => { options.UseSqlServer(Configuration.GetConnectionString("StudentIdentityDbContext")); });
六、数据库的迁移、创建及更新
然后在 pm控制台 中添加迁移:
添加迁移的语法为 add-migration <迁移类名> -c <具体 DbContext 名>
cd LibraryDemo add-migration LendingInfo -c LibraryDemo.Data.LendingInfoDbContext add-migration StudentIdentity -c LibraryDemo.Data.StudentIdentityDbContext
运行 add-migration 命令会创建 Migrations 文件夹以及相应的迁移快照:
显示的类名为 <创建时间>_<迁移类名>,而实际的类名为 add-migration 后的第一个参数名。
在创建迁移时,EF 会自动为我们创建或更新对应 DbContext 的快照,即其中后缀为 Snapshot 的类。其中会包含当前对应的 DbCOntext 的结构,并会以代码保留相应的约束,如 LendingInfoDbContextModelSnapshot 类:
生成的迁移类 LendingInfo 和 Account 类则有两个方法—— 用于更新数据库的 Up 方法和用以回溯数据库的 Down 方法,可以在这两个方法或者在快照的 BuildModel 方法中使用 Fluent API 对数据库做进一步的改动,并且通过对 Fluent API 的使用可以使我们的类少用 DataAnnotations 以保证类的整洁。
需要注意的是,生成的迁移类中的 Up 和 Down 方法是根据生成迁移之前的数据库快照生成的,如我在之后为 LendingInfoDbContext 添加 DbSet<RecommendedBook> 时,在以上的基础上运行了 add-migration AddRecommendedBook -c LibraryDemo.Data.LendingInfoDbContext ,生成的 Up 方法只包括添加表 RecommendedBooks 的行为,而 Down 方法只包括删除表 RecommendedBooks 的行为。
随后在 pm控制台 执行以下创建或更新数据库:
update-database -c LibraryDemo.Data.LendingInfoDbContext update-database -c LibraryDemo.Data.StudentIdentityDbContext
最后在 SQL server对象管理器 中可以看见创建的数据库以及对应的表:
至此域模型创建工作完成。
补充:
使用命令行对数据库进行迁移及更新有两种方式:
dotnet ef migrations migrationName -c TargetContext dotnet ef database update -c TargetContext
add-migration migrationName -c TargetContext update-Database -c TargetContext
windows 命令行命令不区分大小写,其中 migrationName 为迁移类名,最好提供有意义的命名;而 TargetContext 为目标 DbContext 类名,需要使用带有命名空间的完全命名。
如果需要删除数据库则使用 drop 方法
drop-database -c TargetContext
而为 update 方法指定迁移类则可以回溯数据库。
Update-Database LendingInfoDbContext -TargetMigration:"20181127081115_LendingInfo.cs"
- ASP.NET Core 打造一个简单的图书馆管理系统(三)基本登录页面以及授权逻辑的建立
- ASP.NET Core 打造一个简单的图书馆管理系统(四)密码修改以及密码重置
- ASP.NET Core 打造一个简单的图书馆管理系统(二)Code First 多对多关系的建立
- ASP.NET Core 打造一个简单的图书馆管理系统(九) 学生信息增删(终章)
- ASP.NET Core 打造一个简单的图书馆管理系统(五)初始化书籍信息
- ASP.NET Core 打造一个简单的图书馆管理系统(七)外借/阅览图书信息的增删改查
- sql server 关于表中只增标识问题 C# 实现自动化打开和关闭可执行文件(或 关闭停止与系统交互的可执行文件) ajaxfileupload插件上传图片功能,用MVC和aspx做后台各写了一个案例 将小写阿拉伯数字转换成大写的汉字, C# WinForm 中英文实现, 国际化实现的简单方法 ASP.NET Core 2 学习笔记(六)ASP.NET Core 2 学习笔记(三)
- asp.net core 身份认证/权限管理系统简介及简单案例
- 一步步打造基于ASP.NET的CMS内容管理系统--Step2 系统配置(附源代码)
- Asp.Net Core 项目实战之权限管理系统(3) 通过EntityFramework Core使用PostgreSQL
- Asp.Net 简单考题管理系统
- 一步一步使用Ext JS MVC与Asp.Net MVC 3开发简单的CMS后台管理系统之调整首页显示
- 欢迎阅读daxnet的新博客:一个基于Microsoft Azure、ASP.NET Core和Docker的博客系统
- php-简单后台图书管理系统-数据库表的创建以及pdo方式数据库的封装工具类01
- 【商业版】C# ASP.NET 通用权限管理系统组件源码中的数据库访问组件可以全面支持Access单机数据库了
- C# ASP.NET 权限设计 完全支持多数据库多语言包的通用权限管理系统组件源码
- 一步一步使用Ext JS MVC与Asp.Net MVC 3开发简单的CMS后台管理系统之完成登录功能
- C# ASP.NET 走火入魔通用权限管理系统组件V3.2试用版下载地址【含数据库设计文档、使用手册】
- Asp.Net Core 项目实战之权限管理系统(1) 使用AdminLTE搭建前端
- Asp.Net Core 项目实战之权限管理系统(8) 功能菜单的动态加载