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 主键自动增长。
一、对图书馆系统域模型的分析
一个图书馆系统需要有管理员、 学生、书架以及书籍
域模型,即用来存储数据的模型。
在此域模型可以用以下结构创建:
二、项目结构
然后就可以开始建立该项目了:
三、建立域模型
学位枚举:
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(, MinimumLength = )]
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; }
}
书架信息:
由于 EF 会自动将 int 类型的主键设置为自动增长,因此自定义 Bookshelf 的 ID 在插入数据库时会报错,在此需添加修饰 [DatabaseGenerated(DatabaseGeneratedOption.None)] 告知 ef 取消该设置:
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(, MinimumLength = )]
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 MVC 打造一个简单的图书馆管理系统 (修正版)(一) 基本模型以及数据库的建立的更多相关文章
- ASP.NET Core MVC 打造一个简单的图书馆管理系统 (修正版)(二)数据库初始化、基本登录页面以及授权逻辑的建立
前言: 本系列文章主要为我之前所学知识的一次微小的实践,以我学校图书馆管理系统为雏形所作. 本系列文章主要参考资料: 微软文档:https://docs.microsoft.com/zh-cn/asp ...
- ASP.NET Core MVC 打造一个简单的图书馆管理系统 (修正版)(七) 学生信息增删
前言: 本系列文章主要为我之前所学知识的一次微小的实践,以我学校图书馆管理系统为雏形所作. 本系列文章主要参考资料: 微软文档:https://docs.microsoft.com/zh-cn/asp ...
- ASP.NET Core MVC 打造一个简单的图书馆管理系统 (修正版)(六)学生借阅/预约/查询书籍事务
前言: 本系列文章主要为我之前所学知识的一次微小的实践,以我学校图书馆管理系统为雏形所作. 本系列文章主要参考资料: 微软文档:https://docs.microsoft.com/zh-cn/asp ...
- ASP.NET Core MVC 打造一个简单的图书馆管理系统 (修正版)(五)外借/阅览图书信息的增删改查
前言: 本系列文章主要为我之前所学知识的一次微小的实践,以我学校图书馆管理系统为雏形所作. 本系列文章主要参考资料: 微软文档:https://docs.microsoft.com/zh-cn/asp ...
- ASP.NET Core MVC 打造一个简单的图书馆管理系统 (修正版)(四)图书信息的增删改查
前言: 本系列文章主要为我之前所学知识的一次微小的实践,以我学校图书馆管理系统为雏形所作. 本系列文章主要参考资料: 微软文档:https://docs.microsoft.com/zh-cn/asp ...
- ASP.NET Core MVC 打造一个简单的图书馆管理系统 (修正版)(三)密码修改以及密码重置
前言: 本系列文章主要为我之前所学知识的一次微小的实践,以我学校图书馆管理系统为雏形所作. 本系列文章主要参考资料: 微软文档:https://docs.microsoft.com/zh-cn/as ...
- 002.Create a web API with ASP.NET Core MVC and Visual Studio for Windows -- 【在windows上用vs与asp.net core mvc 创建一个 web api 程序】
Create a web API with ASP.NET Core MVC and Visual Studio for Windows 在windows上用vs与asp.net core mvc 创 ...
- 在ASP.NET Core MVC中构建简单 Web Api
Getting Started 在 ASP.NET Core MVC 框架中,ASP.NET 团队为我们提供了一整套的用于构建一个 Web 中的各种部分所需的套件,那么有些时候我们只需要做一个简单的 ...
- Pro ASP.NET Core MVC 第6版 第二章(前半章)
目录 第二章 第一个MVC 应用程序 学习一个软件开发框架的最好方法是跳进他的内部并使用它.在本章,你将用ASP.NET Core MVC创建一个简单的数据登录应用.我将它一步一步地展示,以便你能看清 ...
随机推荐
- 搭建nexus私服,无法下载相关jar包,报错Repository proxy-mode is BLOCKED_AUTO
在搭建nexus私服的时候,之前没直接用来下载maven的相关插件jar包,一直可以使用, 结果今天要编译hadoop的时候,在linux上新用maven就报错了,无法下载maven的相关插件(如下) ...
- 《TCP/IP详解卷1:协议》——第3章 IP:网际协议(转载)
1.引言 IP是TCP/IP协议族中最核心的协议.所有的TCP.UDP.ICMP及IGMP数据都以IP数据报格式传输.IP提供不可靠. 无连接的数据报传送服务. (1)不可靠 它不能保证IP数据报能成 ...
- hihoCoder #1014 : Trie树 [ Trie ]
传送门 #1014 : Trie树 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi和小Ho是一对好朋友,出生在信息化社会的他们对编程产生了莫大的兴趣,他们约定好互 ...
- 文本框变更值触发js事件
//输入数量更新,不需要失去焦点才触发 $(document).on('input', "input[id^='itemquantity']", function () { sav ...
- Working with Validators and Messages in AngularJS
原文:http://odetocode.com/blogs/scott/archive/2014/10/16/working-with-validators-and-messages-in-angul ...
- SQL FULL OUTER JOIN 关键字
SQL FULL OUTER JOIN 关键字 SQL FULL OUTER JOIN 关键字 FULL OUTER JOIN 关键字只要左表(table1)和右表(table2)其中一个表中存在匹配 ...
- UTF-8 GBK UTF8 GB2312之间的区别和关系
UTF-8 GBK UTF8 GB2312之间的区别和关系 UTF-8:Unicode TransformationFormat-8bit,允许含BOM,但通常不含BOM.是用以解决国际上字符 ...
- 使用vscode 编译 sass
由于我在工作中用的编辑器是 vscode ,所以记录一下vscode 编译sass 的配置 vs code 编译saass 1.在扩展里搜索“easy sass”,直接进行安装即可 2.安装后默认已经 ...
- java 配置时遇到的问题及解决办法
1. 最近JDK更新很频繁,以至于我安装时版本太多,选择也会出现问题 首先,确定你选择的是32位版本还是64位版本(貌似64位系统下也可以安装32位的JDK), 这个相当重要,因为这个会影响到ecli ...
- sqlserver中All、Any和Some用法与区别
转自:http://blog.csdn.net/gyc1105/article/details/8063624 SQLServer中有三个关键字可以修改比较运算符:All.Any和Some,其中Som ...