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数据库双机热备的配置方法详解

《MySQL数据库双机热备的配置方法详解》在企业级应用中,数据库的高可用性和数据的安全性是至关重要的,MySQL作为最流行的开源关系型数据库管理系统之一,提供了多种方式来实现高可用性,其中双机热备(M... 目录1. 环境准备1.1 安装mysql1.2 配置MySQL1.2.1 主服务器配置1.2.2 从

SpringBoot基于注解实现数据库字段回填的完整方案

《SpringBoot基于注解实现数据库字段回填的完整方案》这篇文章主要为大家详细介绍了SpringBoot如何基于注解实现数据库字段回填的相关方法,文中的示例代码讲解详细,感兴趣的小伙伴可以了解... 目录数据库表pom.XMLRelationFieldRelationFieldMapping基础的一些代

Redis 基本数据类型和使用详解

《Redis基本数据类型和使用详解》String是Redis最基本的数据类型,一个键对应一个值,它的功能十分强大,可以存储字符串、整数、浮点数等多种数据格式,本文给大家介绍Redis基本数据类型和... 目录一、Redis 入门介绍二、Redis 的五大基本数据类型2.1 String 类型2.2 Hash

Spring Boot分层架构详解之从Controller到Service再到Mapper的完整流程(用户管理系统为例)

《SpringBoot分层架构详解之从Controller到Service再到Mapper的完整流程(用户管理系统为例)》本文将以一个实际案例(用户管理系统)为例,详细解析SpringBoot中Co... 目录引言:为什么学习Spring Boot分层架构?第一部分:Spring Boot的整体架构1.1

Java Instrumentation从概念到基本用法详解

《JavaInstrumentation从概念到基本用法详解》JavaInstrumentation是java.lang.instrument包提供的API,允许开发者在类被JVM加载时对其进行修改... 目录一、什么是 Java Instrumentation主要用途二、核心概念1. Java Agent

C#利用Free Spire.XLS for .NET复制Excel工作表

《C#利用FreeSpire.XLSfor.NET复制Excel工作表》在日常的.NET开发中,我们经常需要操作Excel文件,本文将详细介绍C#如何使用FreeSpire.XLSfor.NET... 目录1. 环境准备2. 核心功能3. android示例代码3.1 在同一工作簿内复制工作表3.2 在不同

使用Node.js和PostgreSQL构建数据库应用

《使用Node.js和PostgreSQL构建数据库应用》PostgreSQL是一个功能强大的开源关系型数据库,而Node.js是构建高效网络应用的理想平台,结合这两个技术,我们可以创建出色的数据驱动... 目录初始化项目与安装依赖建立数据库连接执行CRUD操作查询数据插入数据更新数据删除数据完整示例与最佳

Linux五种IO模型的使用解读

《Linux五种IO模型的使用解读》文章系统解析了Linux的五种IO模型(阻塞、非阻塞、IO复用、信号驱动、异步),重点区分同步与异步IO的本质差异,强调同步由用户发起,异步由内核触发,通过对比各模... 目录1.IO模型简介2.五种IO模型2.1 IO模型分析方法2.2 阻塞IO2.3 非阻塞IO2.4

Python实现简单封装网络请求的示例详解

《Python实现简单封装网络请求的示例详解》这篇文章主要为大家详细介绍了Python实现简单封装网络请求的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录安装依赖核心功能说明1. 类与方法概览2.NetHelper类初始化参数3.ApiResponse类属性与方法使用实

Oracle数据库在windows系统上重启步骤

《Oracle数据库在windows系统上重启步骤》有时候在服务中重启了oracle之后,数据库并不能正常访问,下面:本文主要介绍Oracle数据库在windows系统上重启的相关资料,文中通过代... oracle数据库在Windows上重启的方法我这里是使用oracle自带的sqlplus工具实现的方