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创建一个简单的数据登录应用.我将它一步一步地展示,以便你能看清 ...
随机推荐
- linux下rename用法--批量重命名 转
原文地址:https://www.cnblogs.com/hester/p/5615871.html Linux的rename 命令有两个版本,一个是C语言版本的,一个是Perl语言版本的,早期的Li ...
- input文本框的value属性在页面中不随输入的数据而变化
今天,在做试验遇到这么一个需求: 一个input文本框,输入值后将标签传到后台,在后台解析标签,发现value仍然是初值,不是我们改变后的值. 例如: <input name="&qu ...
- 介绍 JSON的
JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式. 易于人阅读和编写.同时也易于机器解析和生成. 它基于JavaScript Programming Lan ...
- python学习之-- subprocess模块
subprocess 模块 功能:用来生成子进程,并可以通过管道连接它们的输入/输出/错误,以及获得它们的返回值.它用来代替多个旧模块和函数: os.system os.spawn* os.popen ...
- PAT (Advanced Level) 1032. Sharing (25)
简单题,不过数据中好像存在有环的链表...... #include<iostream> #include<cstring> #include<cmath> #inc ...
- Unique Paths II (dp题)
Follow up for "Unique Paths": Now consider if some obstacles are added to the grids. How m ...
- CentOS 6.x Radius
CentOS 6.x Radius 一. 实现环境: 1.系统:CentOS release 6.6 (Final) 2.需要软件包: 1) freeradius-2.1.12-6.e16.x ...
- pagePiling.js - 创建美丽的全屏滚动效果
在线演示 在线演示 本地下载 全屏滚动效果是近期很流行的网页设计形式,带给用户良好的视觉和交互体验. pagePiling.js 这款jQuery插件能够帮助前端开发者轻松实现这样的效果.支持全部的主 ...
- NSUserDefaults 保存自己定义对象
项目里json返回的一个model须要保存下来,这个model是固定的没必须去创建表,想到了NSUserDefaults来存储,暂不考虑安全问题. NSUserDefaults没法直接存储一个对象.在 ...
- 怎样将查询到的数据显示在DataGridView中
背景介绍: 数据库中的T_Line_Info表中存放着学生上机的记录,也就是我们须要查询上机记录的表.当中详细内容为: 界面设计例如以下: watermark/2/text/aHR0cDovL2Jsb ...