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 ...
随机推荐
- Spring Boot 正常启动后访问Controller提示404
问题描述 今天重新在搭建Spring Boot项目的时候遇到访问Controller报404错误,之前在搭建的时候没怎么注意这块.新创建项目成功后,作为项目启动类的Application在com.bl ...
- 黏包现象之udp
老师的博客:http://www.cnblogs.com/Eva-J/articles/8244551.html server端 import socket import subprocess ser ...
- 超哥笔记 --nginx入门(6)
一 NGINX 1 nignx是什么 nginx是一个开源的支持高性能,高并发的web服务和代理服务软件. nginx比他大哥apache性能改进许多,nginx占用的系统资源更少,支持高并发连接,有 ...
- 【Teradata SQL】字符串分割函数STRTOK和STRTOK_SPLIT_TO_TABLE
STRTOK函数: 按照指定分隔符,将字符串分割成多个部分,返回指定部分字符串. 参数说明: (1)instring:字符串或字符串表达式. (2)delimiter:分隔符列表,字符串每个字符都会做 ...
- excel poi导出demo
最近做了一个excel 导出的demo,是抄写老大的(嘻嘻嘻),现在把demo源码放在这里 链接:https://pan.baidu.com/s/1_xj0hej-1xwX5JF39acEOg 提取码 ...
- SQL FOREIGN KEY 约束
SQL FOREIGN KEY 约束 一个表中的 FOREIGN KEY 指向另一个表中的 PRIMARY KEY. 让我们通过一个例子来解释外键.请看下面两个表: "Persons&quo ...
- realm swift调研--草稿
realm swift调研: After you have added the object to the Realm you can continue using it, and all chang ...
- 文本分类实战(五)—— Bi-LSTM + Attention模型
1 大纲概述 文本分类这个系列将会有十篇左右,包括基于word2vec预训练的文本分类,与及基于最新的预训练模型(ELMo,BERT等)的文本分类.总共有以下系列: word2vec预训练词向量 te ...
- 文本分类实战(三)—— charCNN模型
1 大纲概述 文本分类这个系列将会有十篇左右,包括基于word2vec预训练的文本分类,与及基于最新的预训练模型(ELMo,BERT等)的文本分类.总共有以下系列: word2vec预训练词向量 te ...
- 【Consul】CONSUL调研
[Consul]CONSUL调研 2016年08月18日 18:31:53 YoungerChina 阅读数:1962更多 所属专栏: Consul修炼 版权声明:原创不易,转载请注明出处! ht ...