EF6 和 EF Core 之间的行为变更

下面是包含 EF6 和 EF Core 之间的行为变更的非完整列表。 移植应用程序时,务必牢记它们,因为这些可能会更改应用程序的行为方式,而在交换到 EF Core 后它们不会显示为编译错误。

它用作迁移过程中需要考虑的概要检查事项。 有关更详细的逐个案例说明,请阅读详细案例

DbSet.Add/Attach 和图形行为

在 EF6 中,在实体上调用 DbSet.Add() 将递归搜索导航属性引用的所有实体。 所找到的上下文未在跟踪的任何实体也会被标记为“已添加”。 DbSet.Attach() 的行为相同,但会将所有实体标记为“未更改”。

EF Core 执行相似的递归搜索,但有些规则略有不同。

  • 如果为生成的密钥配置了根实体,并且未设置密钥,则会将该实体置于 Added 状态。
  • 适用于递归搜索导航属性期间找到的所有实体:
    • 若实体的主键由存储生成
      • 若主键未设置为值,状态将设置为“已添加”。 若为主键值的属性类型分配了 CLR 默认值(如为 int 分配 0,为 string 分配 null 等),则视为“未设置”它。
      • 若主键设置为值,状态将设置为“未更改”。
    • 若主键非由数据库生成,则将实体置于与根相同的状态。
  • 此行为变更仅适用于 AttachUpdate 方法组。 Add 始终将实体置于 Added 状态,即使设置了密钥也是如此。
  • Attach 方法将设置了密钥的实体置于 Unchanged 状态。 这有助于实现“如果为新则插入它,否则不管它。”Update 方法将设置了密钥的实体置于 Modified 状态。 这有助于实现“如果为新则插入它,否则更新它。”

此处的一般理念是,Update 是处理断开连接实体的插入和更新的一种非常简单的方法。 它可确保插入任何新实体,并更新任何现有实体。

同时,Add 还提供了一种简单的强制插入实体的方式。 仅当不使用存储生成的密钥时,添加功能最为有用,因为在这种情况下 EF 不知道实体是否为新实体。

有关 EF Core 中的这些行为的详细信息,请参阅 EF Core 中的变更跟踪

Code First 数据库初始化

EF6 包含许多关于执行数据库连接和数据库初始化的功能。 这些规则包括:

  • 若未执行任何配置,EF6 将从 SQL Express 或 LocalDb 选择数据库。
  • 若应用程序的 App/Web.config 文件中包含与上下文名称相同的连接字符串,则将使用此连接。
  • 如果数据库不存在,则会创建一个。
  • 若数据库中不存在模型中的任何表,则会将当前模型的架构添加到数据库。 若启用了迁移,则会使用它们创建数据库。
  • 若数据库存在,并且 EF6 此前已创建架构,则将检查架构是否与当前模型兼容。 若在创建架构后模型已更改,将引发异常。

EF Core 不执行任何此类功能。

  • 必须在代码中显式配置数据库连接。
  • 不执行初始化。 必须使用 DbContext.Database.Migrate() 应用迁移(或使用 DbContext.Database.EnsureCreated()/EnsureDeleted() 创建/删除数据库,而不使用迁移)。

Code First 表命名约定

EF6 通过复数形式服务运行实体类名,来评估实体映射到的默认表名称。

EF Core 使用派生的上下文上公开实体的 DbSet 属性的名称。 若实体不包含 DbSet 属性,则使用类名。

有关详细信息,请阅读管理数据库架构