26

我正在使用实体框架 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; }
}

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

  • ID
  • 第1条
  • 第二条
  • 客户1
  • 客户2
  • 制造商
  • 命令
  • 类型

我想让 EF4 共享通用属性,最终得到以下结果:

  • ID
  • 文章
  • 顾客
  • 制造商
  • 命令
  • 类型

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

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

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

但这引发了以下异常:

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

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

4

2 回答 2

20

没有绕过此验证的解决方法。在 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; }
}

这导致所需的架构:

替代文字


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

替代文字

于 2010-12-08T16:51:33.293 回答
8

对于遇到此问题的任何人,它现在已在 EF6 中得到修复: 实体框架 - Codeplex

于 2013-04-02T04:02:28.450 回答