如何在每个层次结构(TPH)映射中共享公用列名称

San*_*zen 24 .net c# mapping entity-framework-4 ef-code-first

我正在使用Entity Framework 4 CTP5代码第一种方法,我有一个每层次表(TPH)映射.层次结构中的某些类具有共同的属性.

public class BaseType
{
    public int Id { get; set; }
}

public class A : BaseType
{
    public string Customer { get; set; }
    public string Order { get; set; }
}

public class B : BaseType
{
    public string Customer { get; set; }
    public string Article { get; set; }
}

public class C : BaseType
{
    public string Article { get; set; }
    public string Manufacturer { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

默认约定将此映射到以下列:

  • ID
  • 第1条
  • 第二条
  • customer1表
  • 顾客2
  • 生产厂家
  • 订购
  • 类型

我希望让EF4共享公共属性,最终得到以下结果:

  • ID
  • 文章
  • 顾客
  • 生产厂家
  • 订购
  • 类型

除了减少列数之外,这还具有能够基于文章搜索记录的优点,而无需知道哪些类型具有Article属性.

我尝试将每个公共属性映射到同一列:

modelBuilder.Entity<B>().Property(n => n.Article).HasColumnName("Article");
modelBuilder.Entity<C>().Property(n => n.Article).HasColumnName("Article");
Run Code Online (Sandbox Code Playgroud)

但是这引起了以下异常:

指定的架构无效.错误:(36,6):错误0019:类型中的每个属性名称必须是唯一的.已定义属性名称"文章".

有谁知道如何绕过这个验证规则?

Mor*_*avi 18

没有解决方法可以绕过此验证.在TPH中,列要么属于所有子级继承的基类,要么专用于子类.您不能指示EF将其映射到您的两个孩子,而不是另一个孩子.尝试这样做(例如通过[Column(Name = "Customer")]同时放置A.Customer和B.Customer)将导致MetadataException并显示以下消息:

指定的架构无效.错误:(10,6):错误0019:类型中的每个属性名称必须是唯一的.已定义属性名称"客户".


TPH解决方案:

一种解决方法是促进CustomerArticle属性的基类:

public class BaseType {
    public int Id { get; set; }
    public string Customer { get; set; }
    public string Article { get; set; }
}

public class A : BaseType {
    public string Order { get; set; }
}

public class B : BaseType { }

public class C : BaseType {
    public string Manufacturer { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

这导致了所需的架构:

替代文字


TPT解决方案(推荐):

也就是说,我建议考虑使用每种类型的表(TPT),因为它更适合您的场景:

public class BaseType
{
    public int Id { get; set; }
}

public class A : BaseType
{
    [Column(Name = "Customer")]
    public string Customer { get; set; }
    public string Order { get; set; }
}

public class B : BaseType
{
    [Column(Name = "Customer")]
    public string Customer { get; set; }

    [Column(Name = "Article")]
    public string Article { get; set; }
}

public class C : BaseType
{
    [Column(Name="Article")]
    public string Article { get; set; }
    public string Manufacturer { get; set; }
}

public class MyContext : DbContext
{
    public DbSet<BaseType> BaseTypes { get; set; }        

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<BaseType>().ToTable("BaseType");
        modelBuilder.Entity<A>().ToTable("A");
        modelBuilder.Entity<C>().ToTable("C");
        modelBuilder.Entity<B>().ToTable("B");          
    }
}
Run Code Online (Sandbox Code Playgroud)

替代文字

  • 您所建议的内容可能会起作用,但它会污染类层次结构并破坏OO的目的. (2认同)
  • 同意.这就是为什么我建议你使用TPT,如我更新的答案所示. (2认同)

Ben*_*Ben 8

对于任何遇到此问题的人,现在已经在EF6:Entity framework - Codeplex中修复了它