EF CodeFirst系列(2)---CodeFirst的数据库初始化
1. CodeFirst的默认约定
1.领域类和数据库架构的映射约定
在介绍数据库的初始化之前我们需要先了解领域类和数据库之间映射的一些约定。在CodeFirst模式中,约定指的是根据领域类(如Student,Grade类)自动配置概念模型的一些默认规则。在上一节的小栗子中,我们没有在领域类中做任何配置,但是EF API帮我们配置了主外键、关系、列的数据类型等,这就是约定在起作用。下表中列除了一些默认的CodeFirst约定:
默认规则 | 描述 |
Schema | EF创建所有的DB对象都放在dbo架构中。dbo.Students |
Table Name | 实体名的复数,如Student->Students |
Foreign key |
默认情况,EF会找和主实体的主键名一样名字的列 如果没有的话EF创建一个导航属性名_导航属性主键形式的外键, 如:在dbo.Students表中,外键是Grade_GradeId |
列顺序 |
EF创建的数据库列的数据和领域类属性的顺序一致,唯一可能不一致的是会把主键放在第一位 |
映射(mapping) |
默认EF会把领域类的所有属性都映射到数据库,可以通过[NotMapped]实现领域类/属性的不映射 |
级联删除 |
默认启用所有的类型关系 |
下表显示了C#数据类型到SqlServer数据类型的映射:
bool | bit |
byte | tinyint |
short | smallint |
int | int |
long | bigint |
float | real |
double | float |
decimal | decimal(18,2) |
string | nvrchar(Max) |
datetime | datetime |
byte[] | varbinary(Max) |
下图显示了领域类和数据库架构的映射:
2.一些补充
当我们使用导航属性时,EF6中把1对多关系作为默认关系。
注意:EF6中不包含1对1,多对多的默认关系,我们需要自己通过Fluent API或者注释属性进行配置。这些以后会介绍。当EFAPI找不到主键时,CodeFist模式会给这个类创建为复杂类型(Complex Type)。
2.EF确定数据库的名字的方式
前边我们知道了数据库中表名,列名,主外键名是怎么来的,但是数据库的名字是怎么确定的呢?下图展示了数据库初始化的工作流程,在我们创建SchoolContext(继承于DbContext)时,通过给父类的构造函数传值来确定数据库的名字
通过上图,上下文类的父构造函数可以接受如下的参数:
1.无参数
2.数据库名字
3.连接字符串名字
1.无参数
如果不向父构造函数传参,EF会在local SQLEXPRESS中创建数据库,名字是{NameSpace}.{Context Name}。我们上节的栗子中,创建的数据库名字就是:EF6Console.SchoolContext
namespace EF6Console
{
public class SchoolContext : DbContext
{
public SchoolContext():base() { }
public virtual DbSet<Student> Students { get; set; }
public virtual DbSet<Grade> Grades { get; set; } }
}
2.数据库名字作为参数
namespace EF6Console
{
public class SchoolContext : DbContext
{
public SchoolContext():base("MySchoolDb") { }
public virtual DbSet<Student> Students { get; set; }
public virtual DbSet<Grade> Grades { get; set; } }
}
如上边的代码所示, 我们把自己想取的名字(如MySchoolDb)传入base即可,EF会在local SQLEXPRESS中帮我们创建一个名字为MySchoolDb的数据库。
3.连接字符串名字
我们也可以通过给base传入连接字符串名字来确定数据库名字,传入连接字符串的格式是:"name=yourConnectionString",注意这个是固定格式,如果不加“name=”的话,EF会认为我们传入的是数据库名字。
namespace EF6Console
{
public class SchoolContext : DbContext
{
public SchoolContext():base("name=SchoolDbConnectionString") { }
public virtual DbSet<Student> Students { get; set; }
public virtual DbSet<Grade> Grades { get; set; }
}
}
App.config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<connectionStrings>
<add name="SchoolDbConnectionString"
connectionString="Data Source=.;Initial Catalog=SchoolDB-ByConnectionString;Integrated Security=true"
providerName="System.Data.SqlClient"/>
</connectionStrings>
</configuration>
在上边的SchoolContext类中我们把连接字符串的名字作为参数传入,EF会在app.config或web.config找到连接字符串,获取数据库的名字(SchoolDB-ByConnectionString),然后使用现有的数据库,连接字符串中的数据库不存在就在本地Sql Server数据库中新建一个名为SchoolDB-ByConnectionString的数据库(不一定都要是Sql Server,后边会介绍在MySql中生成数据库)。
3.数据库初始化策略
前边我们已经在运行程序时生成了数据库,也知道了数据库初始化的基本流程,但是有一些新的问题:我们再次运行程序会创建一个新的数据库吗?生产环境怎么去配置?数据库生成后如果我们改变了领域类怎么办?为了解决这些问题我们必须有一个数据库迁移策略。
1.四种初始化器
EF中有四种数据库的初始化器:
1.CreateDatabaseIfNotExists:这是默认的初始化器。这种初始化器在第一次运行程序时会创建数据库,再次运行不会再创建新的数据库。但是如果我们改变了领域类,运行程序时会抛出一个异常,这在前边的小栗子中已经演示过了。
2.DropCreateDatabaseIfModelChanges:如果领域类发生了改变,删除以前的数据库,然后重建一个新的。采用这种初始化器我们不用再担心领域类改变影响数据库架构的问题。
3.DropCreateDatabaseAlways:使用这种初始化器,我们每次运行程序都会删除以前的数据库,重建新的数据库。如果在开发过程中每次都想使用最新的数据库,那么可以采用这种初始化器。
4.Custom DB Initializer:自定义初始化器,如果上边几种都不能满足要求,那么我们可以自己定义一个初始化器。
1.通过代码配置初始化器
使用上边四种任意一个初始化策略我们都要使用Database类,如下:
public class SchoolDBContext: DbContext
{
public SchoolDBContext(): base("SchoolDBConnectionString")
{
Database.SetInitializer<SchoolDBContext>(new CreateDatabaseIfNotExists<SchoolDBContext>()); //Database.SetInitializer<SchoolDBContext>(new DropCreateDatabaseIfModelChanges<SchoolDBContext>());
//Database.SetInitializer<SchoolDBContext>(new DropCreateDatabaseAlways<SchoolDBContext>());
//Database.SetInitializer<SchoolDBContext>(new SchoolDBInitializer());//自定义初始化器
} public DbSet<Student> Students { get; set; }
public DbSet<Standard> Standards { get; set; }
}
自定义的初始化器SchoolDBInitializer继承以上几种初始化器(这里继承CreateDatabaseIfNotExists),如下:
public class SchoolDbInitializer : CreateDatabaseIfNotExists<SchoolDBContext>
{
protected override void Seed(SchoolDbContext context)
{
base.Seed(context);
}
}
2.通过配置文件配置初始化器
我们可以在配置文件中配置初始化器:
①内置的初始化器
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="DatabaseInitializerForType EF6Console.SchoolDBContext, EF6Console"
value="System.Data.Entity.DropCreateDatabaseAlways`1[[EF6Console.SchoolDBContext, EF6Console]], EntityFramework" />
</appSettings>
</configuration>
②自定义初始化器
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="DatabaseInitializerForType EF6Console.SchoolDBContext, EF6Console"
value="EF6Console.SchoolDBInitializer, EF6Console" />
</appSettings>
</configuration>
2.关闭初始化器
① 通过代码关闭
public class SchoolDBContext: DbContext
{
public SchoolDBContext() : base("SchoolDBConnectionString")
{
//关闭初始化器
Database.SetInitializer<SchoolDBContext>(null);
}
public DbSet<Student> Students { get; set; }
public DbSet<Standard> Standards { get; set; }
}
② 通过配置文件关闭
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="DatabaseInitializerForType EF6Console.SchoolDBContext,EF6Console"
value="Disabled" />
</appSettings>
</configuration>
EF CodeFirst系列(2)---CodeFirst的数据库初始化的更多相关文章
- EF CodeFirst系列(9)---添加初始化数据和数据库迁移策略
1.添加初始化数据(Seed) 我们可以在初始化数据库的过程中给数据库添加一些数据.为了实现初始化数据(seed data)我们必须创建一个自定义的数据库初始化器(DB initializer),并重 ...
- 4.DB Initialization(数据库初始化)[EF Code-First系列]
前面的例子中,我们已经看到了Code-First自动为我们创建数据库的例子. 这里我们将要学习的是,当初始化的时候,Code-First是怎么决定数据库的名字和服务的呢??? 下面的图,解释了这一切! ...
- 20.翻译系列:Code-First中的数据库迁移技术【EF 6 Code-First系列】
原文链接:https://www.entityframeworktutorial.net/code-first/migration-in-code-first.aspx EF 6 Code-First ...
- 2.简单的Code First例子(EF Code-First系列)
现在假想,我们想要为讴歌学校创建一个应用程序,这个程序需要能够来添加或者更新学生,分数,教师还有课程信息. 代替之前我们的做法:先是创建数据库,现在我们不这么做,我们先来创建领域类,首先我来创建两个简 ...
- 3.Code-First 约定(EF Code-First系列)
前面,我们已经了解了Code-First利用领域类,怎么为我们创建数据库的简单示例.现在我们来学习一下Code-First约定吧. 什么是约定 约定说白了,就是基于一套规矩办事,这里就是基于你定义好的 ...
- 10.Configure One-to-Many(配置一对多关系)【Code-First系列】
现在,我们将学习怎么配置一对多的关系. Visit Entity Relationship section to understand how EF manages one-to-one, one-t ...
- 9.Configure One-to-One(配置一对一关系)【Code-First系列】
现在,开始学习怎么配置一对一的关系,众所周知,一对一的关系是:一个表中的主键,在另外一个表中,同时是主键和外键[实际上是一对零或者一对一]. 请注意:一对一的关系,在MS SQL Server中,技术 ...
- 11.Configure Many-to-Many(配置多对多关系)【Code-First系列】
现在学习EF Code-First多对多的配置. 这里我们举例:学生和班级实体,一个学生可以选修多个课程,多个学生也可以选修同一个课程. 一.使用数据注解特性,配置多对多的关系 using Syste ...
- 8.Fluent API in Code-First【Code-First系列】
在前面的章节中,我们已经看到了各种不同的数据注解特性.现在我们来学习一下Fluent API. Fluent API是另外一种配置领域类的方式,它提供了更多的配置相比数据注解特性. Mappings[ ...
- 5.翻译系列:EF 6中数据库的初始化(EF 6 Code-First 系列)
原文地址:http://www.entityframeworktutorial.net/code-first/database-initialization-in-code-first.aspx EF ...
随机推荐
- Win10 - MySQL 5.7 忘记密码
Win10 - MySQL 5.7 忘记密码 # 关闭 mysql 服务 net stop mysql # 在命令行输入以下命令, 输入后新建一个 CMD 窗口 mysqld -nt --skip-g ...
- SQLServer之CHECK约束
CHECK约束添加规则 1.CHECK 约束用于限制列中的值的范围. 2.Check约束通过逻辑表达式来判断数据的有效性,用来限制输入一列或多列的值的范围,在列中更新数据时,所要输入的内容必须满足Ch ...
- OKR相关4本书,好书3本
最近几年看过4本OKR相关的书,有3本是4星.其中第一本是最近看的,剩下3本是2017年看的. OKR源自德鲁克和格鲁夫,跟谷歌是天作之合:4星|<这就是OKR> 4星|<OKR实践 ...
- centos7源码包安装Mongodb,并设置开机自启动
1.下载源码包 curl -O https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-3.2.12.tgz 2.解压 放到 /usr/local/ ...
- DeveloperGuide Hive UDAF
Writing GenericUDAFs: A Tutorial User-Defined Aggregation Functions (UDAFs) are an excellent way to ...
- Python编码规范(PEP8)及奇技淫巧(不断更新)
https://blog.csdn.net/MrLevo520/article/details/69155636
- centos7下kubernetes(13。kubernetes-探讨service IP)
service cluster IP是一个虚拟IP,是由kubernetes节点上的iptables规则管理的 通过iptables-save | grep 10.105.215.156看到与clus ...
- np.mgrid的用法
功能:返回多维结构,常见的如2D图形,3D图形 np.mgrid[ 第1维,第2维 ,第3维 , …] 第n维的书写形式为: a:b:c c表示步长,为实数表示间隔:该为长度为[a,b),左开右闭 或 ...
- 解决 AttributeError: 'ForeignKey' object has no attribute 're'
解决办法 # print('rel...',filter_field_obj.re.to.objects.all()) print("rel...", filter_field_o ...
- 【学习总结】GirlsInAI ML-diary day-18-下载/保存excel
[学习总结]GirlsInAI ML-diary 总 原博github链接-day18 使用Python来操作excel文件 Excel的处理与DataFrame格式是分不开的 可以理解为DataFr ...