我正在使用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; }
}
默认约定将其映射到以下列:
我希望让EF4共享公共属性,最终得到以下结果:
除了列数减少之外,这还有一个优点,就是可以根据文章搜索记录,而不必知道哪些类型确实具有Article属性。
我尝试将每个公共属性映射到同一列:
modelBuilder.Entity<B>().Property(n => n.Article).HasColumnName("Article");
modelBuilder.Entity<C>().Property(n => n.Article).HasColumnName("Article");
但是这引发了以下异常:
指定的架构无效。错误:(36,6):错误0019:类型中的每个属性名称必须是唯一的。属性名称“文章”已经定义。
有谁知道如何绕过此验证规则?
答案 0 :(得分:18)
没有解决方法可以绕过此验证。在TPH中,列要么属于所有子级继承的基类,要么专用于子类。您无法指示EF将其映射到您的两个孩子,而不是另一个孩子。尝试这样做(例如将[Column(Name = "Customer")]
放在A.Customer和B.Customer上)将导致 MetadataException 并显示以下消息:
指定的架构无效。错误: (10,6):错误0019:类型中的每个属性名称必须是唯一的。已定义属性名称“客户”。
解决此问题的一个方法是将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; }
}
结果是所需的架构:
那就是说,我建议考虑使用每种类型的表(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");
}
}
答案 1 :(得分:8)
对于遇到此问题的任何人,现在已在EF6中修复: Entity framework - Codeplex