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)
默认约定将此映射到以下列:
我希望让EF4共享公共属性,最终得到以下结果:
除了减少列数之外,这还具有能够基于文章搜索记录的优点,而无需知道哪些类型具有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:类型中的每个属性名称必须是唯一的.已定义属性名称"客户".
一种解决方法是促进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; }
}
Run Code Online (Sandbox Code Playgroud)
这导致了所需的架构:

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