EF继承与表拆分

时间:2017-09-13 21:14:46

标签: c# entity-framework

我试图将两个不同的EF模型映射到同一个表SharedTable,让我们称它们为EntityA和EntityB。我让它们都扩展了一个名为BaseEntity的基本实体。

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");
        });
    }
}

我得到的错误说:

类型&#39; System.NotSupportedException&#39;的第一次机会异常。发生在EntityFramework.dll

其他信息:类型&#39; EntityB&#39;无法按定义映射,因为它映射了使用实体拆分或其他形式的继承的类型的继承属性。选择不同的继承映射策略,以便不映射继承的属性,或更改层次结构中的所有类型以映射继承的属性,并且不使用拆分。

有什么方法吗?

1 个答案:

答案 0 :(得分:0)

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

您有三种类型:一种基本类型BaseEntity和两种派生类型EntityAEntityB。你决定将它们分成三个单独的表格。 BaseEntityEntityA的{​​{1}}属性将放在一个表格中。 EntityBEntityA每个都有EntityB表中基本属性的外键。

此继承策略是否最适合您的问题,取决于您是否主要查询BaseEntity那个......或者实体A BaseEntities EntityB` ...考虑使用Table per concrete class (TPC)

TPT继承策略意味着每个查询/的连接......使用基类属性。如果您使用TPC,则不需要此加入。但是,每当你要求“BaseEntities”时,TPC都需要一个Concat ...所以这取决于你最常做什么样的查询,哪种继承策略最适合你的需要。

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

  • 您不希望任何人自行存储EntityA个对象。如果你允许这样做,它就不会是继承,而是一对一或零关系:每个BaseEntity属于一个EntityA,每个{{1} }}有一个或一个'EntityA BaseEntity BaseEntity BaseEntity EntityA . This is not what you want: every EntityB has exactly either one / or one '只有一个&#39; BaseEntity` < / LI>
  • 由于您不想存储, and every 'EntityA个对象,因此BaseEntity`类应该被声明为抽象,就像TPT的给定链接一样。
  • EntityB en BaseEntity的类定义中,请勿提及EntityA表的外键。再次,请参阅TPT的给定链接
  

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

  • 在您的模型构建中,仅提及表名称,如果需要,还提及列名称。不要提外键

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

顺便问一下,整数上的[Required]是否有用?即使我想,我也不能给这个整数一个空值。你不是指[Key]吗?正如您所追随的那样entity framework code first conventions即使这是不必要的。