全国电子音乐交流中心

【EntityFramework系列】入门干货

歆视界2020-07-31 13:04:27
  • Entity Framework介绍

Entity Framework是微软的Object Relational Mapper(对象关系映射器),它可以让应用程序开发者将关系型数据作为业务模型来使用,也消除了开发者为数据访问编写的绝大多数管道代码的需要。体系结构如下图:

  • EDM、DbContext说明

Entity Framework是依赖概念数据模型(Entity Data Model)来完成工作的。概念数据模型是Entity Framework的核心。要使用Entity Framework,必须创建概念数据模型,即EDM。EDM定义了概念模型类、类之间的关系以及模型到数据库模式之间的映射。

Entity Framework可以将数据库暴露成对象的集合,前提需要了解DbContext,这个类是Entity Framework Code First的核心,在高层次上是数据库抽象。DbContext有泛型集合属性,每个属性的类型是DbSet<TRowType>,对应于每个表。集合中的每个对象指的是一个实体,代表相应表中的一行。数据表中的列是定义在TRowType类中的属性。

DbContext类是EF中的主要对象。它负责:

a) 管理数据库连接

b) 提供执行CRUD操作的支持

c) 追踪模型的更改,目的在于在数据库中更新模型

DbContext类可以理解成管理EDM中所有实体的东西,让我们为这些实体执行所有的数据库操作。当我们对一个对象执行CRUD时,必须调用DbContext类中的SaveChanges方法。

  • 三种开发风格

Database First

用于已存在数据库模式的方法。使用这种方法,EDM是从数据库模式中生成的。最适合于使用了已经存在的数据库的应用。

Code First

这种方法中,所有的领域模型都是以类的形式编写的。这些类会建立我们的EDM,数据库模式会从这些类中创建。这种方法最适合于那些高度以领域为中心并且领域模型类创建优先的应用程序。这里需要的数据库只是为了这些领域模型的持久化机制。

Model First

这种方法和Code First方法很相似,但是这种情况下我们使用了EDM视觉设计器来设计我们的模型。数据库模式和类将会通过这个概念模型生成。该模型将会给我们创建数据库的SQL语句,然后我们可以使用它来创建数据库并连接应用程序。

  • 配置数据库结构的三种方式

特性(数据注解)

这些特性类位于System.ComponentModel.DataAnnotaions命名空间。

下面是常用的用于重写默认的约定的特性:

Table:指定该类要映射到数据库中的表名

Column:指定类的属性要映射到数据表中的列名

Key:指定该属性是否以主键对待

TimeStamp:将该属性标记为数据库中的时间戳列

ForeignKey:指定一个导航属性的外键属性

NotMapped:指定该属性不应该映射到数据库中的任何列

DatabaseGenerated:指定属性应该映射到数据表中计算的列。也可以用于映射到自动增长的数据库表。

此外,数据注解也用作验证特性。如果持久化数据时,模型对象的属性值和数据注解所标记的不一致,就会抛异常。

FluentAPI

DbContext类有一个OnModelCreating方法,它用于流利地配置领域类到数据库模式的映射。在数据库上下文中的OnModelCreating方法中使用Fluent API来定义表的数据库模式。使用fluent API的一个重要决定因素是我们是否使用了外部的POCO类,即实体模型类是否来自一个类库。我们无法修改类库中类的定义,所以不能通过数据注解来提供映射细节。这种情况,我们必须使用fluent API。FluentAPI详细用法参考https://msdn.microsoft.com/en-us/library/jj591617(v=vs.113).aspx

配置伙伴类

配置伙伴类继承EntityTypeConfiguration<T>,为每个实体类单独创建一个配置伙伴类。然后在OnModelCreating方法中调用这些配置伙伴类。


示例:

public class AMap:EntityTypeConfiguration<A>

{

    public AMap()

    {

        ToTable("AFromConfig");

        Property(m => m.Name).IsRequired();

        HasColumnName("AName");

    }

}

 

在数据库上下文中调用

protected override void OnModelCreating(DbModelBuilder modelBuilder) {

    modelBuilder.Configurations.Add(new AMap());

    base.OnModelCreating(modelBuilder);

}

  • 数据库连接及初始化策略

首先来看一下数据库上下文类继承的DbContext的构造函数有以下几种重构:

可以看出,管理数据库连接的主要方式有两种:

连接字符串

可以是连接字符串,也可以是工程配置文件中的配置项name值,也可以为空(EF默认用数据库上下文类名作为配置项name值去查找配置文件)。

DbConnection对象

对数据库上下文类使用已经存在的数据库连接,可直接传入Connection对象,注意bool参数的设置。


注:配置文件中和数据库上下文类名同名的连接字符串优先权更大。


EF在创建数据库之前,会使用数据库初始化器将从领域实体中提取到的模式信息推送给数据库。数据库初始化器常用的初始化策略有以下几种:CreateDatabaseIfNotExists、DropCreateDatabaseAlways、DropCreateDatabaseIfModelChanges、MigrateDatabaseToLatestVersion。

其中,CreateDatabaseIfNotExists是默认初始化策略。

如果要覆盖这个策略,那么需要在DbContext类中的构造函数中使用Database.SetInitializer方法。

  • 填充种子数据

为了向数据库插入一些初始化数据,可以通过在数据库初始化器类中派生数据来实现。

假设我们使用的是DropCreateDatabaseAlways数据库初始化策略,那么初始化器类就要从该泛型类继承,并传入数据库上下文作为类型参数。接下来,要种子化数据库就要重写DropCreateDatabaseAlways类的Seed方法,而Seed方法拿到了数据库上下文,因此我们可以使用它来将数据插入数据库。

  • 懒加载和预加载

懒加载是直到查询的结果被枚举时,该查询涉及到的相关实体才会从数据库加载。如果加载的实体包含了其他实体的导航属性,那么直到用户访问该导航属性时,这些相关的实体才会被加载。

使用Code First时,懒加载依赖于导航属性的本质。如果导航属性是virtual修饰的,那么懒加载就开启了,如果要关闭懒加载,不要给导航属性加virtual关键字就可以了。如果想要为所有的实体关闭懒加载,那么可以在数据库中的上下文中去掉实体集合属性的virtual关键字即可。

预加载是当我们要加载查询中的主要实体时,同时也加载与之相关的实体。要实现预加载,我们要使用Include方法。

示例:dbContext.Users.Include("Roles") .ToList();

  • 数据库迁移

这里简单介绍一些在Nuget包管理控制台窗口中执行的数据库迁移相关脚本命令。前提是选对进行迁移操作的默认项目。

Add-Migration  新建数据库迁移脚本

Enable-Migrations 给项目启动数据库迁移

Get-Help  帮助命令

Update-Database [-Script]  更新数据库命令 [生成脚本参数]


入门知识先简单介绍到这里,像视图、存储、异步API、并发、事务等,这里暂不进行介绍。因为目前工作中,我也没有用到,以后用到了,再深入学习介绍。

下期预告:【EntityFramework系列】入门湿货(手把手带你创建一个简单的使用EntityFramework的工程)。