2017-09-13 92 views
1

我想映射两个不同的EF模型到同一个表SharedTable,让我们称他们为EntityA和EntityB。我让它们都扩展了一个名为BaseEntity的基本实体。EF继承与表拆分

EntityA仅与SharedTable字段一起定义,EntityB在SharedTable和EntityBTable中具有字段。

 modelBuilder.Entity<BaseEntity>() 
      .Map<EntityA>(m => m.Requires("IsEntityA").HasValue<bool>(true)) 
      .Map<EntityB>(m => m.Requires("IsEntityA").HasValue<false>(true)); 

     modelBuilder.Configurations.Add(new EntityBMap()); 
     modelBuilder.Configurations.Add(new EntityAMap()); 
     modelBuilder.Configurations.Add(new BaseEntityMap()); 

的模型看起来像这样

public class BaseEntity 
{ 
    [Required] 
    public int Id { get; set; } 
    public int SharedTableField1 { get; set; } 
} 

public class EntityA : BaseEntity 
{ 
    public int SharedTableField2 { get; set; } 
} 

public class EntityB : BaseEntity 
{ 
    public int EntityBTableField1 { get; set; } 
} 

的映射是

public class BaseEntityMap : EntityTypeConfiguration<BaseEntity> 
{ 
    public BaseEntityMap() 
    { 
     // Primary Key 
     this.HasKey(t => t.Id); 

     this.ToTable("SharedTable"); 
     this.Property(t => t.Id).HasColumnName("Id"); 
     this.Property(t => t.SharedTableField1).HasColumnName("SharedTableField1"); 
    } 
} 

public class EntityAMap : EntityTypeConfiguration<EntityA> 
{ 
    public EntityAMap() 
    { 
     this.HasKey(t => t.Id); 
     this.Property(t => t.Id).HasColumnName("Id"); 
     this.ToTable("SharedTable"); 
     this.Property(t => t.SharedTableField2).HasColumnName("SharedTableField2"); 
    } 
} 

public class EntityBMap : EntityTypeConfiguration<EntityB> 
{ 
    public EntityBMap() 
    { 
     Map(c => 
     { 
      HasKey(t => t.Id); 
      Property(t => t.Id).HasColumnName("Id"); 
      c.Properties(t => new 
      { 
       t.SharedTableField2 
      }); 
      c.ToTable("SharedTable"); 
     }); 

     Map(c => 
     { 
      c.Properties(t => new 
      { 
       t.EntityBTableField1 
      }); 
      c.ToTable("EntityBTable"); 
     }); 
    } 
} 

我得到的错误说:

'System.NotSupportedException' 类型的第一次机会异常发生在EntityFramework.dll中

附加信息:类型'EntityB'不能按照定义进行映射,因为它将继承的属性映射到使用实体分割或其他形式的继承的类型。选择不同的继承映射策略,以便不映射继承的属性,或者更改层次结构中的所有类型以映射继承的属性,并且不使用拆分。

任何方法?

+0

为什么要将't.EntityBTableField1'映射到另一个表? (这被称为*实体分割*)。 –

+0

将它存储在另一个表中是有意义的,因为它不会在所有记录中使用,因此在不需要获取时会减少检索的数据量。 – MaPi

+0

这可能是有意义的,如果它是关于大型对象或实际上昂贵的计算域。我不会担心几个int或其他小类型。你也可以使用投影('Select(x => new {...}')来限制查询结果中的字段数量。 –

回答

0

您选择的继承策略是Table per Type (TPT)

您有三种类型:一种基本类型BaseEntity和两种派生类型EntityAEntityB。你决定把它们分成三个独立的表格。 EntityAEntityBBaseEntity属性将被放在一张表中。 EntityAEntityB每个都有BaseEntity表中的基本属性的外键。

这是否继承策略是最适合你的问题取决于你是否将主要查询BaseEntities那......还是“EntityA / EntityB`说......请考虑使用Table per concrete class (TPC)

的TPT继承策略意味着对于每个查询EntityA的加入,其中...使用基类属性。如果您使用TPC,则不需要此连接。但是,无论何时您询问'BaseEntities`,TPC都需要一个Concat ......因此,这取决于您最常做哪种类型的查询,哪种继承策略最适合您的需求。

如果你想坚持战略TPT,似乎你不建立你的模型正确。

  • 你不希望任何人自己存储BaseEntity对象。如果你允许,它不会是继承,但一到零或一的关系:每EntityA属于一个BaseEntity,每BaseEntity有零或一个“EntityA . This is not what you want: every BaseEntity has exactly either one EntityA or one ' EntityB , and every 'EntityA/EntityB只有一个'BaseEntity`
  • 由于您不想存储BaseEntity对象,所以'BaseEntity`类应该声明为抽象的,就像给定的TPT链接一样。
  • EntityA en EntityB的类定义中,请不要提及BaseEntity表的外键。另外,请给定链路的TPT

我认为抽象基类和缺乏外键是让实体框架知道你选择 继承策略TPT的 关键信息。

  • 在你的建筑模型,仅在需要的列名提表名和。不要提及外键

当我像这样构建模型时,实体框架像TPT一样创建了三个表。任何额外的流畅的API或属性都是需要的。尽管我没有提到外键,实体框架知道它们需要作为多态关联。再次看到链接到TPT

顺便说一下,是你的整数[必需]有用吗?即使我想,我也不能给这个整数一个空值。你不是这个意思吗?正如您所遵循entity framework code first conventions即使这不是必要的。