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

时间:2022-09-23 21:24:20

I'm using Entity Framework 4 CTP5 code first approach and I have a Table per Hierarchy (TPH) mapping. Some of my classes in the hierarchy have properties in common.

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

The default convention maps this to the following columns:

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

  • Id
  • ID
  • Article1
  • 第1条
  • Article2
  • 第二条
  • Customer1
  • customer1表
  • Customer2
  • 顾客2
  • Manufacturer
  • 生产厂家
  • Order
  • 订购
  • Type
  • 类型

I want to have EF4 share the common properties to end up with the following:

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

  • Id
  • ID
  • Article
  • 文章
  • Customer
  • 顾客
  • Manufacturer
  • 生产厂家
  • Order
  • 订购
  • Type
  • 类型

Apart from the reduced number of columns, this has the advantage of being able to search for records based on Article for example, without having to know which types exactly have an Article property.

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

I tried mapping each common property to the same column:

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

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

but this threw the following exception:

但是这引起了以下异常:

Schema specified is not valid. Errors: (36,6) : error 0019: Each property name in a type must be unique. Property name 'Article' was already defined.

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

Does anyone know how to get around this validation rule?

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

2 个解决方案

#1


17  

There is no workaround to bypass this validation. In TPH a column is either belongs to the base class which is inherited by all childs or is specialized to the child class. You cannot instruct EF to map it to two of your childs but not for the other. Attempting to do so (for example by putting [Column(Name = "Customer")] on both A.Customer and B.Customer) will be causing a MetadataException with this message:

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

Schema specified is not valid. Errors: (10,6) : error 0019: Each property name in a type must be unique. Property name 'Customer' was already defined.

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


TPH Solution:

One solution to this would be to promote Customer and Article properties to the base class:

解决此问题的一种方法是将Customer和Article属性提升到基类:

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

Which results to the desired schema:

这导致所需的架构:

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


TPT Solution (Recommended):

That said, I recommend to consider using Table per Type (TPT) since it's a better fit for your scenario:

也就是说,我建议考虑使用每种类型的表(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");          
    }
}

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

#2


7  

For anyone who was having trouble with this issue, it has now been fixed in EF6: Entity framework - Codeplex

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

#1


17  

There is no workaround to bypass this validation. In TPH a column is either belongs to the base class which is inherited by all childs or is specialized to the child class. You cannot instruct EF to map it to two of your childs but not for the other. Attempting to do so (for example by putting [Column(Name = "Customer")] on both A.Customer and B.Customer) will be causing a MetadataException with this message:

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

Schema specified is not valid. Errors: (10,6) : error 0019: Each property name in a type must be unique. Property name 'Customer' was already defined.

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


TPH Solution:

One solution to this would be to promote Customer and Article properties to the base class:

解决此问题的一种方法是将Customer和Article属性提升到基类:

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

Which results to the desired schema:

这导致所需的架构:

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


TPT Solution (Recommended):

That said, I recommend to consider using Table per Type (TPT) since it's a better fit for your scenario:

也就是说,我建议考虑使用每种类型的表(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");          
    }
}

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

#2


7  

For anyone who was having trouble with this issue, it has now been fixed in EF6: Entity framework - Codeplex

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