首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >实体框架: TPC MapInheritedProperties模型超类属性

实体框架: TPC MapInheritedProperties模型超类属性
EN

Stack Overflow用户
提问于 2016-11-16 15:00:16
回答 2查看 2.1K关注 0票数 0

摘要:在实体框架中,我使用TPC创建来自同一个基类的两个类。在fluent API中,我映射继承的属性,但是如何建模基类的属性?

更广泛的描述在实体框架我有一个班级的孩子,和两种类型的孩子:男孩和女孩。男孩和女孩都来自于儿童:

代码语言:javascript
复制
public class Child
{
    public int Id {get; set;}
    public string Name {get; set;}
}
public class Boy : Child
{
    public string SomeBoyishProperty {get; set;}
}
public class Girl : Child
{
    public string SomeGirlyProperty {get; set;}
}

我想要一张有男孩的桌子和一张女孩的桌子,每一张桌子都有孩子的属性。

代码语言:javascript
复制
public class MyDbContext : DbContext
{
    public DbSet<Boy> Boys {get; set;}
    public DbSet<Girl> Girls {get; set;
}

从几个来源,例如,这个我了解到这被称为TPC:每一个具体类的表,并且我应该在OnModelCreating中进行MapInheritedProperties

代码语言:javascript
复制
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);

    // model the properties of the base class, for instance set max length
    modelBuilder.Entity<Child>()
        .Property(p => p.Name).IsRequired().HasMaxLength(12);

    // Model Daughter:
    modelBuilder.Entity<Daughter>()
    .Map(m =>
    {
        m.MapInheritedProperties();
        m.ToTable("Daughters");
    })
    .Property(p => p.SomeGirlyProperty).IsOptional().HasMaxLength(13);

    // model Boy
    modelBuilder.Entity<Son>()
    .Map(m =>
    {
        m.MapInheritedProperties();
        m.ToTable("Sons");
    })
    .Property(p => p.SomeBoyishProperty).IsOptional().HasMaxLength(14);
}

在SaveChanges期间,我得到一个InvlidOperationException,指示主键不是唯一的。删除生成Child的部分解决了此问题。

如何在“女孩”和“男孩”中创建“儿童”属性而不必这样做?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-11-16 23:14:40

简短回答:

如果希望代码工作,请删除模型配置中对Child实体的任何引用。一旦EF知道Child作为实体,它将强制执行以下规则:不能有两个类型为Child的实体,也不能有两个从内存中具有相同PK的Child继承的实体。您可以看到错误告诉您,成功持久化的实体;但是当EF提取新ID时,它发现两个实体都具有相同的ID。

长答案

删除

代码语言:javascript
复制
modelBuilder.Entity<Child>()
    .Property(p => p.Name).IsRequired().HasMaxLength(12);

相反,OnModelCreating方法应该是这样的。

代码语言:javascript
复制
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);

    // Model Daughter:
    var girlEntity = modelBuilder.Entity<Girl>();
    girlEntity.Map(m =>
    {
        m.MapInheritedProperties();
        m.ToTable("Daughters");
    });
    girlEntity.Property(p => p.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
    girlEntity.Property(p => p.Name).IsRequired().HasMaxLength(12);
    girlEntity.Property(p => p.SomeGirlyProperty).IsOptional().HasMaxLength(13);

    // model Boy
    var boyEntity = modelBuilder.Entity<Boy>();
    boyEntity.Map(m =>
    {
        m.MapInheritedProperties();
        m.ToTable("Sons");
    });
    boyEntity.Property(p => p.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
    boyEntity.Property(p => p.Name).IsRequired().HasMaxLength(12);
    boyEntity.Property(p => p.SomeBoyishProperty).IsOptional().HasMaxLength(14);
}

如果不希望在配置中重复配置,我将使用基类上的DataAnnotations属性强制执行所需的名称。

还需要强制执行要在数据库中自动生成的Id属性。在fluent API中使用Map方法时,约定不会发生这种情况。您可以看到,我添加了fluent调用,以便在GirlBoy映射中实现这一点。

希望这能有所帮助。

票数 4
EN

Stack Overflow用户

发布于 2016-11-17 08:06:19

我重新设计了阿图罗的解决方案。这个解决方案太长了,不能用评论来形容。所以Arturo:谢谢你给我的想法,。起首语!

Arturo建议使用数据注释。我不想使用该方法的原因是,类的建模不需要与特定的数据库表示形式相对应。我有点假设,但如果我想要一个男孩的名字比一个女孩的名字的最大长度,那么数据注释是没有帮助的。

此外,还有一些事情必须使用fluent API来完成。例如,不能说System.DateTime使用DataAnnotations在数据库中具有DateTime2格式。

如果你还没有猜到的话:我的问题描述非常简单。这三个类都有很多属性,需要大量的fluent API配置。

阿图罗的话帮助我找到了以下解决办法:

代码语言:javascript
复制
internal class ChildConfig<T> : EntityTypeConfiguration<T> where T : Child
{
    public ChildConfig(...)
    {
        // configure all Child properties
        this.Property(p => p.Name)....
    }
}
internal class BoyConfig : ChildConfig<Boy>
{
    public BoyConfig(...) : base (...)
    {
        // the base class will configure the Child properties
        // configure the Boy properties here
        this.Property(p => p.SomeBoyishProperty)...
    }
}

在MyDbContext中:

代码语言:javascript
复制
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Configurations.Add(new BoyConfig(...));
    modelBuilder.Configuration.Add(new GirlConfig(...));
}
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/40635343

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档