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

相关文章

使用Dify访问mysql数据库详细代码示例

《使用Dify访问mysql数据库详细代码示例》:本文主要介绍使用Dify访问mysql数据库的相关资料,并详细讲解了如何在本地搭建数据库访问服务,使用ngrok暴露到公网,并创建知识库、数据库访... 1、在本地搭建数据库访问的服务,并使用ngrok暴露到公网。#sql_tools.pyfrom

Java实现数据库图片上传功能详解

《Java实现数据库图片上传功能详解》这篇文章主要为大家详细介绍了如何使用Java实现数据库图片上传功能,包含从数据库拿图片传递前端渲染,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1、前言2、数据库搭建&nbsChina编程p; 3、后端实现将图片存储进数据库4、后端实现从数据库取出图片给前端5、前端拿到

IDEA连接达梦数据库的详细配置指南

《IDEA连接达梦数据库的详细配置指南》达梦数据库(DMDatabase)作为国产关系型数据库的代表,广泛应用于企业级系统开发,本文将详细介绍如何在IntelliJIDEA中配置并连接达梦数据库,助力... 目录准备工作1. 下载达梦JDBC驱动配置步骤1. 将驱动添加到IDEA2. 创建数据库连接连接参数

Jmeter如何向数据库批量插入数据

《Jmeter如何向数据库批量插入数据》:本文主要介绍Jmeter如何向数据库批量插入数据方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Jmeter向数据库批量插入数据Jmeter向mysql数据库中插入数据的入门操作接下来做一下各个元件的配置总结Jmete

MySql中的数据库连接池详解

《MySql中的数据库连接池详解》:本文主要介绍MySql中的数据库连接池方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录mysql数据库连接池1、概念2、为什么会出现数据库连接池3、原理4、数据库连接池的提供商5、DataSource数据源6、DBCP7、C

Spring MVC跨域问题及解决

《SpringMVC跨域问题及解决》:本文主要介绍SpringMVC跨域问题及解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录跨域问题不同的域同源策略解决方法1.CORS2.jsONP3.局部解决方案4.全局解决方法总结跨域问题不同的域协议、域名、端口

Java中数组转换为列表的两种实现方式(超简单)

《Java中数组转换为列表的两种实现方式(超简单)》本文介绍了在Java中将数组转换为列表的两种常见方法使用Arrays.asList和Java8的StreamAPI,Arrays.asList方法简... 目录1. 使用Java Collections框架(Arrays.asList)1.1 示例代码1.

StarRocks数据库详解(什么是StarRocks)

《StarRocks数据库详解(什么是StarRocks)》StarRocks是一个高性能的全场景MPP数据库,支持多种数据导入导出方式,包括Spark、Flink、Hadoop等,它采用分布式架构,... 目录StarRocks介绍什么是StarRocks?StarRocks适合什么场景?StarRock

Windows环境下安装达梦数据库的完整步骤

《Windows环境下安装达梦数据库的完整步骤》达梦数据库的安装大致分为Windows和Linux版本,本文将以dm8企业版Windows_64位环境为例,为大家介绍一下达梦数据库的具体安装步骤吧... 目录环境介绍1 下载解压安装包2 根据安装手册安装2.1 选择语言 时区2.2 安装向导2.3 接受协议

Spring AI与DeepSeek实战一之快速打造智能对话应用

《SpringAI与DeepSeek实战一之快速打造智能对话应用》本文详细介绍了如何通过SpringAI框架集成DeepSeek大模型,实现普通对话和流式对话功能,步骤包括申请API-KEY、项目搭... 目录一、概述二、申请DeepSeek的API-KEY三、项目搭建3.1. 开发环境要求3.2. mav