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

Posted

技术标签:

【中文标题】在实体框架中的抽象类上配置自动增量字段【英文标题】:Configuring an Auto Increment field on an Abstract Class in Entity Framework 【发布时间】:2016-05-06 04:18:36 【问题描述】:

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

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 实体上执行相同的操作,它正确地将标识属性添加到 Animals 表中的 ID 列,但是当我尝试将新实体添加到SaveChanges() 方法上的数据库:

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

如何正确地将抽象类型上的 ID 列设置为自动递增,并使其在添加数据时起作用?

【问题讨论】:

请链接您的 dbcontext 类的相关部分 @AlexanderDerck:完成。 注意到你在动物和狗上都有ID,而DogAnimal继承它 啊,是的,当我写这个问题时,那是一个错误。我的真实班级在具体班级中没有 ID。我会解决的。 我还将添加第二个具体类,以进一步阐明我的真实结构是什么样的。 【参考方案1】:

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

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; 

【讨论】:

感谢您的回答,但这不是我想要的。我想要一个 Animal 表,它具有映射到抽象类型的 auto-inc 主键,以及 1 个或多个共享由继承 Animal 的外键链接的相同 ID 的表。 只需将他指定的属性放在你的 Animal Abstract 类中。 我已经尝试过了...如果我通过类的属性指定,或者在 OnModelCreating 中进行指定,则没有任何区别...相同的结果。 实际上,添加[DatabaseGenerated(...)] 属性有效...不知道为什么我第一次尝试时没有这样做。不过我不想要这个界面。谢谢。【参考方案2】:

有了这些模型...

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)

这是你想要的,对吧?

参考: Inheritance with EF Code First: Part 2 – Table per Type (TPT)

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

【讨论】:

【参考方案3】:

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

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

【讨论】:

以上是关于在实体框架中的抽象类上配置自动增量字段的主要内容,如果未能解决你的问题,请参考以下文章

蓝牙与 Android 上的 Qt。通过抽象类上的jni调用java类

spring-data-jpa实体类继承抽象类如何映射父类的属性到数据库

GetIt/Injectable 在抽象类上缺少可注入装饰器?

在 Controller 抽象类上添加方法

使用 PHPUnit 测试受保护方法的最佳实践(在抽象类上)

抽象类上的 Json.reads(不支持密封特征:没有已知的子类)