KeysKeys

键充当每个实体实例的唯一标识符。 EF 中的大多数实体都有一个键,此键映射到关系数据库中主键的概念(对于没有键的实体,请参阅无键实体)。 实体可以有超过主键的其他键(有关详细信息,请参阅备用键)。

按照约定,将名为 Id<type name>Id 的属性配置为实体的主键。

  1. class Car
  2. {
  3. public string Id { get; set; }
  4. public string Make { get; set; }
  5. public string Model { get; set; }
  6. }
  7. class Truck
  8. {
  9. public string TruckId { get; set; }
  10. public string Make { get; set; }
  11. public string Model { get; set; }
  12. }

备注

拥有的实体类型使用不同的规则来定义密钥。

可以将单个属性配置为实体的主键,如下所示:

  1. class Car
  2. {
  3. [Key]
  4. public string LicensePlate { get; set; }
  5. public string Make { get; set; }
  6. public string Model { get; set; }
  7. }
  1. protected override void OnModelCreating(ModelBuilder modelBuilder)
  2. {
  3. modelBuilder.Entity<Car>()
  4. .HasKey(c => c.LicensePlate);
  5. }

你还可以将多个属性配置为实体的键,这称为组合键。 复合密钥只能使用熟知的 API 进行配置;约定将永远不会设置组合键,你不能使用数据批注来配置它。

  1. protected override void OnModelCreating(ModelBuilder modelBuilder)
  2. {
  3. modelBuilder.Entity<Car>()
  4. .HasKey(c => new { c.State, c.LicensePlate });
  5. }

主键名称Primary key name

按照约定,使用名称 PK_<type name>创建关系数据库主键。 可以按如下所示配置 primary key 约束的名称:

  1. protected override void OnModelCreating(ModelBuilder modelBuilder)
  2. {
  3. modelBuilder.Entity<Blog>()
  4. .HasKey(b => b.BlogId)
  5. .HasName("PrimaryKey_BlogId");
  6. }

键类型和值Key types and values

虽然 EF Core 支持使用任何基元类型的属性作为主键,包括 stringGuidbyte[] 和其他类型,但并非所有数据库都支持将所有类型作为键。 在某些情况下,可以自动将键值转换为支持的类型,否则应手动指定转换。

在将新实体添加到上下文时,键属性必须始终具有非默认值,但某些类型将由数据库生成。 在这种情况下,当添加实体进行跟踪时,EF 会尝试生成一个临时值。 在调用SaveChanges后,临时值将替换为数据库生成的值。

重要

如果某个键属性的值由数据库生成,而在添加实体时指定了一个非默认值,则 EF 将假定该实体在数据库中已存在,并且将尝试对其进行更新而不是插入一个新的值。 若要避免这种情况,请禁用值生成或了解如何为生成的属性指定显式值

备用键Alternate Keys

除了主键外,备用键还可用作每个实体实例的替代唯一标识符;它可用作关系的目标。 使用关系数据库时,这将映射到备用键列上的唯一索引/约束和引用列的一个或多个外键约束的概念。

提示

如果只是想要在列上强制唯一性,请定义唯一索引而不是备用键(请参阅索引)。 在 EF 中,备用键为只读,并在唯一索引之上提供附加语义,因为它们可用作外键的目标。

系统通常会在需要时为你引入备用键,你无需手动配置它们。 按照约定,当您标识的属性不是作为关系目标的主键时,将为您引入备用密钥。

  1. class MyContext : DbContext
  2. {
  3. public DbSet<Blog> Blogs { get; set; }
  4. public DbSet<Post> Posts { get; set; }
  5. protected override void OnModelCreating(ModelBuilder modelBuilder)
  6. {
  7. modelBuilder.Entity<Post>()
  8. .HasOne(p => p.Blog)
  9. .WithMany(b => b.Posts)
  10. .HasForeignKey(p => p.BlogUrl)
  11. .HasPrincipalKey(b => b.Url);
  12. }
  13. }
  14. public class Blog
  15. {
  16. public int BlogId { get; set; }
  17. public string Url { get; set; }
  18. public List<Post> Posts { get; set; }
  19. }
  20. public class Post
  21. {
  22. public int PostId { get; set; }
  23. public string Title { get; set; }
  24. public string Content { get; set; }
  25. public string BlogUrl { get; set; }
  26. public Blog Blog { get; set; }
  27. }

你还可以将单个属性配置为备用密钥:

  1. protected override void OnModelCreating(ModelBuilder modelBuilder)
  2. {
  3. modelBuilder.Entity<Car>()
  4. .HasAlternateKey(c => c.LicensePlate);
  5. }

你还可以将多个属性配置为备用密钥(称为复合备用密钥):

  1. protected override void OnModelCreating(ModelBuilder modelBuilder)
  2. {
  3. modelBuilder.Entity<Car>()
  4. .HasAlternateKey(c => new { c.State, c.LicensePlate });
  5. }

最后,按照约定,为备用键引入的索引和约束将被命名为 AK_<type name>_<property name> (对于复合备用键 <property name> 变成以下划线分隔的属性名称列表)。 您可以配置备用密钥的 index 和 unique 约束的名称:

  1. protected override void OnModelCreating(ModelBuilder modelBuilder)
  2. {
  3. modelBuilder.Entity<Car>()
  4. .HasAlternateKey(c => c.LicensePlate)
  5. .HasName("AlternateKey_LicensePlate");
  6. }