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

时间:2010-12-08 15:33:18

标签: c# .net entity-framework-4 ef-code-first mapping

我正在使用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; }
}

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

  • 编号
  • 第一条
  • 第二条
  • customer1表
  • 顾客2
  • 制造商
  • 顺序
  • 类型

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

  • 编号
  • 文章
  • 客户
  • 制造商
  • 顺序
  • 类型

除了列数减少之外,这还有一个优点,就是可以根据文章搜索记录,而不必知道哪些类型确实具有Article属性。

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

modelBuilder.Entity<B>().Property(n => n.Article).HasColumnName("Article");
modelBuilder.Entity<C>().Property(n => n.Article).HasColumnName("Article");

但是这引发了以下异常:

  

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

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

2 个答案:

答案 0 :(得分: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; }
}

结果是所需的架构:

alt text


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

alt text

答案 1 :(得分:8)

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