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的数据库初始化的更多相关文章

  1. EF CodeFirst系列(9)---添加初始化数据和数据库迁移策略

    1.添加初始化数据(Seed) 我们可以在初始化数据库的过程中给数据库添加一些数据.为了实现初始化数据(seed data)我们必须创建一个自定义的数据库初始化器(DB initializer),并重 ...

  2. 4.DB Initialization(数据库初始化)[EF Code-First系列]

    前面的例子中,我们已经看到了Code-First自动为我们创建数据库的例子. 这里我们将要学习的是,当初始化的时候,Code-First是怎么决定数据库的名字和服务的呢??? 下面的图,解释了这一切! ...

  3. 20.翻译系列:Code-First中的数据库迁移技术【EF 6 Code-First系列】

    原文链接:https://www.entityframeworktutorial.net/code-first/migration-in-code-first.aspx EF 6 Code-First ...

  4. 2.简单的Code First例子(EF Code-First系列)

    现在假想,我们想要为讴歌学校创建一个应用程序,这个程序需要能够来添加或者更新学生,分数,教师还有课程信息. 代替之前我们的做法:先是创建数据库,现在我们不这么做,我们先来创建领域类,首先我来创建两个简 ...

  5. 3.Code-First 约定(EF Code-First系列)

    前面,我们已经了解了Code-First利用领域类,怎么为我们创建数据库的简单示例.现在我们来学习一下Code-First约定吧. 什么是约定 约定说白了,就是基于一套规矩办事,这里就是基于你定义好的 ...

  6. 10.Configure One-to-Many(配置一对多关系)【Code-First系列】

    现在,我们将学习怎么配置一对多的关系. Visit Entity Relationship section to understand how EF manages one-to-one, one-t ...

  7. 9.Configure One-to-One(配置一对一关系)【Code-First系列】

    现在,开始学习怎么配置一对一的关系,众所周知,一对一的关系是:一个表中的主键,在另外一个表中,同时是主键和外键[实际上是一对零或者一对一]. 请注意:一对一的关系,在MS SQL Server中,技术 ...

  8. 11.Configure Many-to-Many(配置多对多关系)【Code-First系列】

    现在学习EF Code-First多对多的配置. 这里我们举例:学生和班级实体,一个学生可以选修多个课程,多个学生也可以选修同一个课程. 一.使用数据注解特性,配置多对多的关系 using Syste ...

  9. 8.Fluent API in Code-First【Code-First系列】

    在前面的章节中,我们已经看到了各种不同的数据注解特性.现在我们来学习一下Fluent API. Fluent API是另外一种配置领域类的方式,它提供了更多的配置相比数据注解特性. Mappings[ ...

  10. 5.翻译系列:EF 6中数据库的初始化(EF 6 Code-First 系列)

    原文地址:http://www.entityframeworktutorial.net/code-first/database-initialization-in-code-first.aspx EF ...

随机推荐

  1. django 视图模式

    一 视图 FBV --- function based view(基于函数视图) CBV --- class based view(基于类的视图函数) 二 请求方式 get post put/patc ...

  2. linux磁盘IO读写性能优化

    在LINUX系统中,如果有大量读请求,默认的请求队列或许应付不过来,我们可以 动态调整请求队列数来提高效率,默认的请求队列数存放在/sys/block/xvda/queue/nr_requests 文 ...

  3. vue-router query 传对象需要JSON.stringify()转化

    先说一下场景-微信公众号网页开发中,一个文章列表点击跳转详情页.代码如下 1 2 3 this.$router.push({path: '/wx/detail', query: {res: data} ...

  4. Taro项目遇到的问题

    1. https://taro-ui.aotu.io/#/docs/questions 请在Taro项目根目录找到 config/index.js 文件中的h5项,添加如下: h5: { ... es ...

  5. 3.15 总结,初始java

  6. SpringBoot开发案例之整合Activiti工作流引擎

    前言 JBPM是目前市场上主流开源工作引擎之一,在创建者Tom Baeyens离开JBoss后,JBPM的下一个版本jBPM5完全放弃了jBPM4的基础代码,基于Drools Flow重头来过,目前官 ...

  7. 部署个人wordpress 笔记

    yum list installed | grep php #检查当前安装的PHP包yum remove php.x86_64 php-cli.x86_64 php-common.x86_64 ... ...

  8. swiper 轮播图,拖动之后继续轮播

    在此贴出swiper官网地址:https://www.swiper.com.cn/api/index.html 示例如下(官网示例): <script> var mySwiper = ne ...

  9. 在nginx上用FastCGI解析PHP

    nginx配置文件: Nginx 默认使用  include enable-php.conf;   通过enable-php.conf 来解析PHP,该文件内容如下 location ~ [^/]\. ...

  10. Gradle打jar包命令