在实体框架中的抽象类上配置“自动增量”字段

本文关键字:自动增量 字段 配置 框架 实体 抽象类 | 更新日期: 2023-09-27 18:32:15

我有一些类似于这些的代码优先实体:

public abstract class Animal {
    public int ID { get; set; }
    public int NumberOfLegs { get; set; }
}
public class Dog : Animal {
    public string OtherDogRelatedStuff { get; set; }
}
public class Bird : Animal {
    public string OtherBirdRelatedStuff { get; set; }
}
public class MyContext : DbContext {
    public IDbSet<Animal> Animals { get; set; }
    protected override void OnModelCreating(DbModelBuilder modelBuilder) {
        var pluraliser = PluralizationService.CreateService(new System.Globalization.CultureInfo("en-GB"));
        modelBuilder.HasDefaultSchema("vs");
        modelBuilder.Types().Configure(t => t.ToTable(pluraliser.Pluralize(t.ClrType.Name)));
        // This next line doesn't give ID column IDENTITY(1,1)
        modelBuilder.Entity<Animal>().Property(_ => _.ID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        // This line puts IDENTITY(1,1) on Animal.ID, but causes errors when I try to add/update data.
        //modelBuilder.Entity<Dog>().Property(_ => _.ID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        base.OnModelCreating(modelBuilder);
    }        
}

我想要每种类型的表格...所以表格看起来像这样:

CREATE TABLE Animals (
    ID INT NOT NULL IDENTITY(1,1),
    NumberOfLegs INT NOT NULL,
    CONSTRAINT pkAnimals PRIMARY KEY (ID)
)
CREATE TABLE Dogs (
    ID INT NOT NULL,
    OtherDogRelatedStuff VARCHAR(200),
    CONSTRAINT pkDogs PRIMARY KEY (ID),
    CONSTRAINT fkAnimal_Dog FOREIGN KEY (ID) REFERENCES Animals(ID)
)
CREATE TABLE Birds (
    ID INT NOT NULL,
    OtherBirdRelatedStuff VARCHAR(200),
    CONSTRAINT pkBirds PRIMARY KEY (ID),
    CONSTRAINT fkAnimal_Bird FOREIGN KEY (ID) REFERENCES Animals(ID)
)

数据如下所示:

---Animals----------
ID      NumberOfLegs
1       4
2       4
3       2
---Dogs---------------------
ID      OtherDogRelatedStuff
1       Woof1
2       Woof2
---Birds---------------------
ID      OtherCatRelatedStuff
3       Sqwark1

但是我无法使自动增量ID正常工作或正确配置。

我试过这个:

modelBuilder.Entity<Animal>().Property(_ => _.ID)
    .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

但是由于Animal是抽象的,这似乎并没有在表上设置IDENTITY(1,1)属性。

我也尝试对Dog实体执行相同的操作,这会将 identity 属性正确添加到 Animals 表中的 ID 列,但是当我尝试在 SaveChanges() 方法上向数据库中添加新实体时,我得到了一个UpdateException

A dependent property in a ReferentialConstraint is mapped to a store-generated column. Column: 'ID'.

如何才能将抽象类型的ID列正确设置为自动递增,并在添加数据时使其正常工作?

在实体框架中的抽象类上配置“自动增量”字段

我会说使用接口或单独的抽象类来放置像这样的常见功能:

public interface Common{
  int ID { get; set; }
}
public class Animal : Common {
[DatabaseGenerated(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity)]    
public int ID { get; set; }
public int NumberOfLegs { get; set; }
}
public class Dog : Common {
    public int ID { get; set; }
    public string OtherDogRelatedStuff { get; set; }
}

有了这些模型...

public abstract class Animal
{
    public int ID { get; set; }
    public int NumberOfLegs { get; set; }
}
public class Dog : Animal
{
    public string OtherDogRelatedStuff { get; set; }
}
public class Bird : Animal
{
    public string OtherBirdRelatedStuff { get; set; }
}

。这在上下文中...

public IDbSet<Animal> Animals { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);
    modelBuilder.Entity<Dog>().ToTable("Dogs");
    modelBuilder.Entity<Bird>().ToTable("Birds");
}

。然后在包管理器中执行Add-Migration "Animals"然后Update-Database -Script

您应该获得:

CREATE TABLE [dbo].[Animals] (
    [ID] [int] NOT NULL IDENTITY,
    [NumberOfLegs] [int] NOT NULL,
    CONSTRAINT [PK_dbo.Animals] PRIMARY KEY ([ID])
)
CREATE TABLE [dbo].[Dogs] (
    [ID] [int] NOT NULL,
    [OtherDogRelatedStuff] [nvarchar](max),
    CONSTRAINT [PK_dbo.Dogs] PRIMARY KEY ([ID])
)
CREATE INDEX [IX_ID] ON [dbo].[Dogs]([ID])
CREATE TABLE [dbo].[Birds] (
    [ID] [int] NOT NULL,
    [OtherBirdRelatedStuff] [nvarchar](max),
    CONSTRAINT [PK_dbo.Birds] PRIMARY KEY ([ID])
)
CREATE INDEX [IX_ID] ON [dbo].[Birds]([ID])
ALTER TABLE [dbo].[Dogs] 
ADD CONSTRAINT [FK_dbo.Dogs_dbo.Animals_ID] FOREIGN KEY ([ID]) 
REFERENCES [dbo].[Animals] ([ID])
ALTER TABLE [dbo].[Birds] 
ADD CONSTRAINT [FK_dbo.Birds_dbo.Animals_ID] FOREIGN KEY ([ID]) 
REFERENCES [dbo].[Animals] ([ID])
INSERT [dbo].[__MigrationHistory]([MigrationId], [ContextKey], [Model], [ProductVersion])
VALUES (N'etc)

这就是你想要的,对吧?

参考:EF 代码优先继承:第 2 部分 – 每个类型的表 (TPT)

请注意,如果最初创建字段时没有标识,则有时可能会遇到使用标识创建的字段的问题(反之亦然)。您可以通过删除并重新创建表来解决此问题:https://stackoverflow.com/a/18917348/150342

我遇到了同样的问题,我在抽象类中使用数据注释修复了它,如下所示:

public abstract class Animal {
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int ID { get; set; }
    public int NumberOfLegs { get; set; }
}