ASP.NET Core MVC 打造一个简单的图书馆管理系统 (修正版)(一) 基本模型以及数据库的建立...

本文主要是介绍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

 

 

本章内容:对图书馆系统组成的简要分析。以及对域模型以及相应数据库的建立。

知识点:Code First、EF 基本使用方法、ASP.NET Core 使用 EF Core 的配置方法、EF 多对多关系的建立、取消 int 主键自动增长。

 

 

一、对图书馆系统域模型的分析

一个图书馆系统需要有管理员、 学生、书架以及书籍

 

域模型,即用来存储数据的模型。

在此域模型可以用以下结构创建:

 

 

 

 二、项目结构

然后就可以开始建立该项目了:

 

 

 

三、建立域模型

学位枚举:

1     public enum Degrees
2     {
3         [Display(Name = "本科生")]
4         CollegeStudent,
5         [Display(Name = "研究生")]
6         Postgraduate,
7         [Display(Name = "博士生")]
8         DoctorateDegree
9     }

 

 图书借阅状态枚举:

 1     public enum BookState
 2     {
 3         /// <summary>
 4         /// 可借阅
 5         /// </summary>
 6         [Display(Name = "正常")]
 7         Normal,
 8 
 9         /// <summary>
10         /// 馆内阅览
11         /// </summary>
12         [Display(Name = "馆内阅览")]
13         Readonly,
14 
15         /// <summary>
16         /// 已借出
17         /// </summary>
18         [Display(Name = "已借出")]
19         Borrowed,
20 
21         /// <summary>
22         /// 被续借
23         /// </summary>
24         [Display(Name = "被续借")]
25         ReBorrowed,
26 
27         /// <summary>
28         /// 被预约
29         /// </summary>
30         [Display(Name = "被预约")]
31         Appointed,
32 
33         [Display(Name = "过期")]
34         Expired
35     }

 

该项目准备使用一个数据库存储学生账户信息,另一个则用于存储学生借书信息:

学生账户信息:

 1     public class Student : IdentityUser
 2     {
 3         /// <summary>
 4         /// 学号
 5         /// </summary>
 6         [ProtectedPersonalData]
 7         [RegularExpression("[UIA]\\d{9}")]
 8         [Display(Name = "学号")]
 9         public override string UserName { get; set; }
10 
11         [Display(Name = "手机号")]
12         [StringLength(14, MinimumLength = 11)]
13         public override string PhoneNumber { get; set; }
14 
15         [Display(Name = "姓名")]
16         public string Name { get; set; }
17         [Display(Name = "学历")]
18         public Degrees Degree { get; set; }
19         [Display(Name = "最大借书数目")]
20         public int MaxBooksNumber { get; set; }
21     }

 

书籍信息:

 1     public class Book
 2     {                                
 3         /// <summary>
 4         /// 二维码
 5         /// </summary>
 6         [Key]
 7         [Display(Name = "二维码")]
 8         [Required(ErrorMessage = "未填写二维码")]
 9         public string BarCode { get; set; }
10 
11         public string ISBN { get; set; }
12 
13         /// <summary>
14         /// 书名
15         /// </summary>
16         [Display(Name = "书名")]
17         public string Name { get; set; }
18 
19         /// <summary>
20         /// 取书号
21         /// </summary>
22         [Display(Name = "取书号")]
23         public string FetchBookNumber { get; set; }
24 
25         /// <summary>
26         /// 所在书架
27         /// </summary>
28         public Bookshelf Bookshelf { get; set; }
29 
30         [Display(Name = "书架号")]
31         public int BookshelfId { get; set; }
32 
33         /// <summary>
34         /// 借出时间
35         /// </summary>
36         [Display(Name = "借出时间")]
37         public DateTime? BorrowTime { get; set; }
38 
39         /// <summary>
40         /// 到期时间
41         /// </summary>
42         [Display(Name = "到期时间")]
43         public DateTime? MatureTime { get; set; }
44 
45         /// <summary>
46         /// 预约最晚借书日期
47         /// </summary>
48         [Display(Name = "预约取书时间")]
49         public DateTime? AppointedLatestTime { get; set; }
50 
51         /// <summary>
52         /// 借阅状态
53         /// </summary>
54         [Display(Name = "书籍状态")]
55         public BookState State { get; set; }
56 
57         /// <summary>
58         /// 持有者,指定外键
59         /// </summary>
60         public StudentInfo Keeper { get; set; }
61         [Display(Name = "持有者学号")]
62         public string KeeperId{ get; set; }
63 
64         [Display(Name = "位置")]
65         public string Location { get; set; }
66 
67         [Display(Name = "分类")]
68         public string Sort { get; set; }
69 
70         public ICollection<AppointmentOrLending> Appointments { get; set; }
71     }

 

书架信息:

由于 EF 会自动将 int 类型的主键设置为自动增长,因此自定义 Bookshelf 的 ID 在插入数据库时会报错,在此需添加修饰 [DatabaseGenerated(DatabaseGeneratedOption.None)] 告知 ef 取消该设置:

 1     public class Bookshelf
 2     {
 3         /// <summary>
 4         /// 书架ID
 5         /// </summary>
 6         [Key]
 7         //不自动增长
 8         [DatabaseGenerated(DatabaseGeneratedOption.None)] 
 9         public int BookshelfId { get; set; }
10 
11         /// <summary>
12         /// 书架的书籍类别
13         /// </summary>
14 
15         [Required]
16         public string Sort { get; set; }               
17         /// <summary>
18         /// 最小取书号
19         /// </summary>
20         [Required]
21         public string MinFetchNumber { get; set; }
22         [Required]
23         public string MaxFetchNumber { get; set; }
24 
25         /// <summary>
26         /// 书架位置
27         /// </summary>
28         [Required]
29         public string Location { get; set; }
30 
31         /// <summary>
32         /// 全部藏书
33         /// </summary>
34         public ICollection<Book> Books { get; set; }
35     }

 

 

由于一个学生可以借阅多本书籍,一本书籍可被多人预约,因此书籍和学生具有多对多的关系,在此引入中间类:

其中的 AppointingDateTime 用来区分中间类包含的书籍是借阅书籍还是预约书籍:

1     public class AppointmentOrLending
2     {
3         public Book Book { get; set; }
4         public string BookId { get; set; }
5         public StudentInfo Student { get; set; }
6         public string StudentId { get; set; }
7         public DateTime? AppointingDateTime { get; set; }
8     }

 

学生借书信息:

在 EF 中多对多关系实际上是两个多对一关系。此处 ICollection 的属性成为导航属性,用来提示 EF  StudentInfo 和 AppointmentOrLending 之间存在着多对一的关系。

 1     public class StudentInfo
 2     {
 3         [Key]
 4         public string UserName { get; set; }
 5 
 6         [Required]
 7         public string Name { get; set; }
 8 
 9         /// <summary>
10         /// 学位,用来限制借书数目
11         /// </summary>
12         [Required]
13         public Degrees Degree { get; set; }
14 
15         /// <summary>
16         /// 最大借书数目
17         /// </summary>
18         [Required]
19         public int MaxBooksNumber { get; set; }
20 
21         /// <summary>
22         /// 已借图书
23         /// </summary>
24         public ICollection<AppointmentOrLending> KeepingBooks { get; set; }
25 
26         public string AppointingBookBarCode { get; set; }
27 
28         [StringLength(14, MinimumLength = 11)]
29         public string PhoneNumber { get; set; }
30 
31         /// <summary>
32         /// 罚款
33         /// </summary>
34         public decimal Fine { get; set; }               
35     }

 

外借/阅览书籍信息:

在约定中,若不指定主键,则 EF 会使用 (类名)+ID 的方式指定或创建主键,在此使用 [Key] 指定主键,使用 [Required] 指定字段为必须,这种可以为属性添加在数据库中的约束或者在视图中的约束的修饰称为 DataAnnotations 。

此处 ICollection 的属性成为导航属性,用来提示 EF  Book 和 AppointmentOrLending 之间存在着多对一的关系。

 1     public class Book
 2     {                                
 3         /// <summary>
 4         /// 二维码
 5         /// </summary>
 6         [Key]
 7         [Display(Name = "二维码")]
 8         [Required(ErrorMessage = "未填写二维码")]
 9         public string BarCode { get; set; }
10 
11         public string ISBN { get; set; }
12 
13         /// <summary>
14         /// 书名
15         /// </summary>
16         [Display(Name = "书名")]
17         public string Name { get; set; }
18 
19         /// <summary>
20         /// 取书号
21         /// </summary>
22         [Display(Name = "取书号")]
23         public string FetchBookNumber { get; set; }
24 
25         /// <summary>
26         /// 所在书架
27         /// </summary>
28         public Bookshelf Bookshelf { get; set; }
29 
30         [Display(Name = "书架号")]
31         public int BookshelfId { get; set; }
32 
33         /// <summary>
34         /// 借出时间
35         /// </summary>
36         [Display(Name = "借出时间")]
37         public DateTime? BorrowTime { get; set; }
38 
39         /// <summary>
40         /// 到期时间
41         /// </summary>
42         [Display(Name = "到期时间")]
43         public DateTime? MatureTime { get; set; }
44 
45         /// <summary>
46         /// 预约最晚借书日期
47         /// </summary>
48         [Display(Name = "预约取书时间")]
49         public DateTime? AppointedLatestTime { get; set; }
50 
51         /// <summary>
52         /// 借阅状态
53         /// </summary>
54         [Display(Name = "书籍状态")]
55         public BookState State { get; set; }
56 
57         /// <summary>
58         /// 持有者,指定外键
59         /// </summary>
60         public StudentInfo Keeper { get; set; }
61         [Display(Name = "持有者学号")]
62         public string KeeperId{ get; set; }
63 
64         [Display(Name = "位置")]
65         public string Location { get; set; }
66 
67         [Display(Name = "分类")]
68         public string Sort { get; set; }
69 
70         public ICollection<AppointmentOrLending> Appointments { get; set; }
71     }

 

 

 

四、创建 DbContext 

学生账户信息数据库:

1     public class StudentIdentityDbContext:IdentityDbContext<Student>
2     {
3         public StudentIdentityDbContext(DbContextOptions<StudentIdentityDbContext> options) : base(options)
4         {
5         }
6     }

 

借阅信息数据库:

为了使 StudentInfo 类的 UserName 和 Book 的 BarCode 共同作为 AppointmentOrLending 中间类的主键,需覆写 OnModelCreating 方法:

至此 StudentInfo 和 Book 的多对多关系正式确立。

 1     public class LendingInfoDbContext:DbContext
 2     {
 3         public LendingInfoDbContext(DbContextOptions<LendingInfoDbContext> options) : base(options)
 4         {
 5         }
 6 
 7         public DbSet<Book> Books { get; set; }
 8         public DbSet<BookDetails> BooksDetail { get; set; }
 9         public DbSet<Bookshelf> Bookshelves { get; set; }
10         public DbSet<RecommendedBook> RecommendedBooks { get; set; }
11         public DbSet<StudentInfo> Students { get; set; }
12         public DbSet<AppointmentOrLending> AppointmentOrLendings { get; set; }
13 
14         protected override void OnModelCreating(ModelBuilder modelBuilder)
15         {
16             base.OnModelCreating(modelBuilder);
17             modelBuilder.Entity<AppointmentOrLending>()
18                 .HasKey(c => new { c.BookId, c.StudentId });
19         }
20     }

于是 Book 和 StudentInfo 之间的多对多关系确立完成。

 

 

 

五、根据约定配置数据库,进行依赖注入

在  appsettings.json 中添加数据库连接字符串。

 1 {
 2   "ConnectionStrings": {
 3     "LendingInfoDbContext": "Server=(localdb)\\mssqllocaldb;Database=LendingInfoDbContext;Trusted_Connection=True;MultipleActiveResultSets=true",
 4     "StudentIdentityDbContext": "Server=(localdb)\\mssqllocaldb;Database=StudentIdentityDbContext;Trusted_Connection=True;MultipleActiveResultSets=true"
 5   },
 6   "Logging": {
 7     "LogLevel": {
 8       "Default": "Warning"
 9     }
10   },
11   "AllowedHosts": "*"
12 }

 

在 Startup.cs 中的 ConfigureServices 方法中对数据库进行配置:

1             services.AddDbContext<LendingInfoDbContext>(options =>
2             {
3                 options.UseSqlServer(Configuration.GetConnectionString("LendingInfoDbContext"));
4             });
5             services.AddDbContext<StudentIdentityDbContext>(options =>
6             {
7                 options.UseSqlServer(Configuration.GetConnectionString("StudentIdentityDbContext"));
8             });

 

 

 

六、数据库的迁移、创建及更新

然后在 pm控制台 中添加迁移:

添加迁移的语法为 add-migration <迁移类名> -c <具体 DbContext 名>

1       cd LibraryDemo
2       add-migration LendingInfo -c LibraryDemo.Data.LendingInfoDbContext
3       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控制台 执行以下创建或更新数据库:

1      update-database -c LibraryDemo.Data.LendingInfoDbContext
2      update-database -c LibraryDemo.Data.StudentIdentityDbContext

 

 

最后在 SQL server对象管理器 中可以看见创建的数据库以及对应的表:

 

 

 

至此域模型创建工作完成。

 

 

 

 

补充:

使用命令行对数据库进行迁移及更新有两种方式:

1  dotnet ef migrations migrationName -c TargetContext
2  dotnet ef database update -c TargetContext

 

1  add-migration migrationName -c TargetContext
2  update-Database -c TargetContext

 

windows 命令行命令不区分大小写,其中 migrationName 为迁移类名,最好提供有意义的命名;而 TargetContext 为目标 DbContext 类名,需要使用带有命名空间的完全命名。

如果需要删除数据库则使用 drop 方法

drop-database -c TargetContext

 

而为 update 方法指定迁移类则可以回溯数据库。

Update-Database LendingInfoDbContext -TargetMigration:"20181127081115_LendingInfo.cs"

转载于:https://www.cnblogs.com/gokoururi/p/10369992.html

这篇关于ASP.NET Core MVC 打造一个简单的图书馆管理系统 (修正版)(一) 基本模型以及数据库的建立...的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/168667

相关文章

MySQL数据库中ENUM的用法是什么详解

《MySQL数据库中ENUM的用法是什么详解》ENUM是一个字符串对象,用于指定一组预定义的值,并可在创建表时使用,下面:本文主要介绍MySQL数据库中ENUM的用法是什么的相关资料,文中通过代码... 目录mysql 中 ENUM 的用法一、ENUM 的定义与语法二、ENUM 的特点三、ENUM 的用法1

Java中调用数据库存储过程的示例代码

《Java中调用数据库存储过程的示例代码》本文介绍Java通过JDBC调用数据库存储过程的方法,涵盖参数类型、执行步骤及数据库差异,需注意异常处理与资源管理,以优化性能并实现复杂业务逻辑,感兴趣的朋友... 目录一、存储过程概述二、Java调用存储过程的基本javascript步骤三、Java调用存储过程示

Go语言数据库编程GORM 的基本使用详解

《Go语言数据库编程GORM的基本使用详解》GORM是Go语言流行的ORM框架,封装database/sql,支持自动迁移、关联、事务等,提供CRUD、条件查询、钩子函数、日志等功能,简化数据库操作... 目录一、安装与初始化1. 安装 GORM 及数据库驱动2. 建立数据库连接二、定义模型结构体三、自动迁

ModelMapper基本使用和常见场景示例详解

《ModelMapper基本使用和常见场景示例详解》ModelMapper是Java对象映射库,支持自动映射、自定义规则、集合转换及高级配置(如匹配策略、转换器),可集成SpringBoot,减少样板... 目录1. 添加依赖2. 基本用法示例:简单对象映射3. 自定义映射规则4. 集合映射5. 高级配置匹

嵌入式数据库SQLite 3配置使用讲解

《嵌入式数据库SQLite3配置使用讲解》本文强调嵌入式项目中SQLite3数据库的重要性,因其零配置、轻量级、跨平台及事务处理特性,可保障数据溯源与责任明确,详细讲解安装配置、基础语法及SQLit... 目录0、惨痛教训1、SQLite3环境配置(1)、下载安装SQLite库(2)、解压下载的文件(3)、

MySQL数据库的内嵌函数和联合查询实例代码

《MySQL数据库的内嵌函数和联合查询实例代码》联合查询是一种将多个查询结果组合在一起的方法,通常使用UNION、UNIONALL、INTERSECT和EXCEPT关键字,下面:本文主要介绍MyS... 目录一.数据库的内嵌函数1.1聚合函数COUNT([DISTINCT] expr)SUM([DISTIN

MySQL追踪数据库表更新操作来源的全面指南

《MySQL追踪数据库表更新操作来源的全面指南》本文将以一个具体问题为例,如何监测哪个IP来源对数据库表statistics_test进行了UPDATE操作,文内探讨了多种方法,并提供了详细的代码... 目录引言1. 为什么需要监控数据库更新操作2. 方法1:启用数据库审计日志(1)mysql/mariad

postgresql数据库基本操作及命令详解

《postgresql数据库基本操作及命令详解》本文介绍了PostgreSQL数据库的基础操作,包括连接、创建、查看数据库,表的增删改查、索引管理、备份恢复及退出命令,适用于数据库管理和开发实践,感兴... 目录1. 连接 PostgreSQL 数据库2. 创建数据库3. 查看当前数据库4. 查看所有数据库

解决未解析的依赖项:‘net.sf.json-lib:json-lib:jar:2.4‘问题

《解决未解析的依赖项:‘net.sf.json-lib:json-lib:jar:2.4‘问题》:本文主要介绍解决未解析的依赖项:‘net.sf.json-lib:json-lib:jar:2.4... 目录未解析的依赖项:‘net.sf.json-lib:json-lib:jar:2.4‘打开pom.XM

从入门到精通MySQL 数据库索引(实战案例)

《从入门到精通MySQL数据库索引(实战案例)》索引是数据库的目录,提升查询速度,主要类型包括BTree、Hash、全文、空间索引,需根据场景选择,建议用于高频查询、关联字段、排序等,避免重复率高或... 目录一、索引是什么?能干嘛?核心作用:二、索引的 4 种主要类型(附通俗例子)1. BTree 索引(