从 EF6 移植到 EF Core 的详细案例

本文档详细介绍了 EF6 和 EF Core 之间的一些特定差异。 移植代码时,请参阅本指南。

配置数据库连接

与 EF Core 相比,EF6 连接到各种数据源的方式之间存在一些差异。 移植代码时,必须了解这些差异。

  • 连接字符串:EF Core 不像 EF6 那样直接支持不同连接字符串的多个构造函数重载。 相反,它依赖于DbContextOptions。 仍然可以在派生类型中提供多个构造函数重载,但需要通过选项映射连接。
  • 配置和缓存:EF Core 支持使用可连接到外部服务提供商的内部基础结构实现更可靠、更灵活的依赖项注入。 应用程序可以管理这种情况,以处理必须刷新缓存的情况。 EF6 版本受到限制,无法刷新。
  • 配置文件:EF6 通过可包含提供程序的配置文件支持配置。 EF Core 需要直接引用提供程序程序集和显式提供程序注册(即UseSqlServer)。
  • 连接工厂:EF6 支持的连接工厂。 EF Core 不支持连接工厂,并且始终需要连接字符串。
  • 日志记录:一般情况下,EF Core 中的日志记录更可靠,并且具有多个优化配置选项。

约定

EF6 支持的自定义(“轻型”)约定和模型约定。 轻型约定类似于 EF Core 的预约定模型配置。 作为模型生成的一部分,支持其他约定。

生成模型后,EF6 会运行约定。 EF Core 在生成模型时应用它们。 在 EF Core 中,可以使用 DbContext 将模型生成与活动会话分离。 可以创建使用约定初始化的模型。

数据验证

EF Core 不支持数据验证,并且仅使用数据注释生成模型和迁移。 从 Web/MVC 到 WinForms 和 WPF 的大多数客户端库都提供要使用的数据验证实现。

即将推出的功能

EF6 中的一些功能尚不存在于 EF Core 中,但已在产品路线图中。

  • EF6 支持每个具体类型一张表 (TPC) 以及“实体拆分”。TPC 在 EF7 的路线图中。
  • EF6 中的存储过程映射允许将创建、更新和删除操作委托给存储过程。 EF Core 目前仅允许映射到读取的存储过程。 EF7 的路线图中提供了创建、更新和删除 (CUD) 支持。
  • EF6 中的复杂类型类似于 EF Core 中的自有类型。 但是,将使用 EF7 中的值对象处理完整的功能集。

保留 ObjectContext

EF Core 使用DbContext而不是ObjectContext。 必须更新使用IObjectContextAdapter的代码。 这有时用于具有PreserveChangesOverwriteChanges合并选项的查询。 有关 EF Core 中的类似功能,请查看Reload方法。

模型配置

EF6 和 EF Core 中的模型设计方式之间存在许多重要差异。 EF Core 缺乏对条件映射的完全支持。 它没有模型生成器版本。

其他差异包括:

类型发现

在 EF Core 中,通过三种方式由引擎发现实体类型:

  • DbContext上公开DbSet<TEntity>,其中TEntity是要跟踪的类型。
  • 从代码中的某个位置引用Set<TEntity>
  • 递归发现发现类型引用的复杂类型(例如,如果Blog引用PostBlog可发现,也会发现Post

扫描派生类型的程序集。

映射

EF6 中的.Map()扩展已替换为 EF Core 中的重载和扩展方法。 例如,可以使用“.HasDiscriminator()”配置每个层次结构一张表 (TPH)。 请参阅:建模继承

继承映射

EF6 支持每个层次结构一张表 (TPH)、每个类型一张表 (TPT) 和每个具体类一张表 (TPC),并在层次结构的不同级别启用不同风格的混合映射。 EF Core 将继续要求继承链以单向(TPT 或 TPH)建模,计划在 EF7 中添加对 TPC 的支持。

请参阅:建模继承

属性

EF6 支持属性的索引属性。 在 EF Core 中,它们应用于类型级别,这应该使需要复合索引的方案更容易。 EF Core 不支持包含数据注释的复合键(即在ColumnAttribute中使用 Order 和KeyAttribute)。

有关详细信息,请参阅:索引和约束

必需和可选

在 EF Core 模型生成中,IsRequired仅配置主体端所需的内容。 HasForeignKey现在配置主体端。 要移植代码,改用.Navigation().IsRequired()更直接。 例如:

EF6:

modelBuilder.Entity<Instructor>()
    .HasRequired(t => t.OfficeAssignment)
    .WithRequiredPrincipal(t => t.Instructor);

EF Core 6:

modelBuilder.Entity<Instructor>()
    .HasOne(t => t.OfficeAssignment)
    .WithOne(t => t.Instructor)
    .HasForeignKey<OfficeAssignment>();

modelBuilder.Entity<Instructor>()
    .Navigation(t => t.OfficeAssignment)
    .IsRequired();

modelBuilder.Entity<OfficeAssignment>()
    .Navigation(t => t.Instructor)
    .IsRequired();

默认情况下,所有内容都可选,因此通常不需要调用.IsRequired(false)

空间支持

EF Core 与第三方库社区库NetTopologySuite集成以提供空间支持。

独立关联

EF Core 不支持独立关联(EDM 概念,允许定义两个实体之间的关系与实体本身无关)。 EF Core 中受支持的类似概念是阴影属性

迁移

EF Core 不支持数据库初始值设定项或自动迁移。 虽然 EF Core 中没有migrate.exe,但可以生成迁移捆绑包

Visual Studio 工具

EF Core 没有设计器,没有从数据库更新模型的功能,也没有模型优先流。 没有反向工程向导,也没有内置模板。

虽然这些功能未随 EF Core 一起提供,但有 OSS 社区项目提供其他工具。 具体来说,EF Core Power Tools提供:

  • 从 Visual Studio 内部进行反向工程,支持数据库项目 (.dacpac)。 包括基于模板的代码自定义。
  • 使用模型图形和脚本对 DbContext 进行可视化检查。
  • 使用 GUI 从 Visual Studio 内管理迁移。

有关社区工具和扩展的完整列表,请参阅:EF Core 工具和扩展

更改跟踪

EF6 和 EF Core 处理更改跟踪的方式之间存在一些差异。 下表汇总了这些差异:

功能 EF6 EF Core
实体状态 添加/附加整个图形 支持导航到分离实体
孤立项 已保留 Deleted
断开连接的自跟踪实体 支持 不支持
突变 对属性执行 对支持字段执行*
数据绑定 .Local .Local.ToObservableCollection.ToBindingList
更改检测 完整图形 每个实体

* 默认情况下,不会在 EF Core 中触发属性通知,因此必须配置通知实体

请注意,EF Core 不会像 EF6 那样频繁地自动调用更改检测。

EF Core 为更改跟踪器引入了详细的DebugView。 要了解详细信息,请阅读更改跟踪器调试

查询

EF6 具有 EF Core 中不存在的一些查询功能。 这些方法包括:

  • 一些常见的 C# 函数和 SQL 函数映射。
  • 截获用于查询和更新的命令树。
  • 支持表值参数 (TVP)。

EF6 具有对延迟加载代理的内置支持。 这是 EF Core 的选择加入包(请参阅延迟加载相关数据)。

EF Core 允许使用FromSQL通过原始 SQL 进行组合。