C# 如何在每个层次结构(TPH)映射的表中共享公共列名
我使用的是EntityFramework4CTP5代码优先的方法,我有一个逐层次表(TPH)映射。层次结构中的某些类具有相同的属性C# 如何在每个层次结构(TPH)映射的表中共享公共列名,c#,.net,entity-framework-4,ef-code-first,mapping,C#,.net,Entity Framework 4,Ef Code First,Mapping,我使用的是EntityFramework4CTP5代码优先的方法,我有一个逐层次表(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
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; }
}
默认约定将此映射到以下列:
- 身份证
- 第1条
- 第二条
- 顾客1
- 顾客2
- 制造商
- 命令
- 类型
- 身份证
- 文章
- 顾客
- 制造商
- 命令
- 类型
modelBuilder.Entity<B>().Property(n => n.Article).HasColumnName("Article");
modelBuilder.Entity<C>().Property(n => n.Article).HasColumnName("Article");
modelBuilder.Entity().Property(n=>n.Article).HasColumnName(“Article”);
modelBuilder.Entity().Property(n=>n.Article).HasColumnName(“Article”);
但这引发了以下异常:
指定的架构无效。错误:(36,6):错误0019:类型中的每个属性名称必须是唯一的。已定义属性名称“Article”
有人知道如何绕过此验证规则吗?没有绕过此验证的解决方法。在TPH中,列要么属于所有子类继承的基类,要么专用于子类。您不能指示EF将其映射到您的两个孩子,但不能映射到另一个孩子。尝试这样做(例如,将
[Column(Name=“Customer”)]
放在A.Customer和B.Customer上)将导致此消息出现MetadataException:
指定的架构无效。错误:
(10,6):错误0019:类型中的每个属性名称必须是唯一的。已定义属性名称“Customer”
TPH解决方案: 一种解决方案是将
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解决方案(推荐):
这样,我建议考虑使用每种类型的表(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");
}
}
公共类基类
{
公共int Id{get;set;}
}
公共类A:基类型
{
[列(Name=“客户”)]
公共字符串Customer{get;set;}
公共字符串顺序{get;set;}
}
公共类B:基类型
{
[列(Name=“客户”)]
公共字符串Customer{get;set;}
[列(Name=“Article”)]
公共字符串项目{get;set;}
}
公共类C:基类型
{
[列(Name=“Article”)]
公共字符串项目{get;set;}
公共字符串制造商{get;set;}
}
公共类MyContext:DbContext
{
公共数据库集基类型{get;set;}
模型创建时受保护的覆盖无效(ModelBuilder ModelBuilder)
{
modelBuilder.Entity().ToTable(“BaseType”);
modelBuilder.Entity().ToTable(“A”);
modelBuilder.Entity().ToTable(“C”);
modelBuilder.Entity().ToTable(“B”);
}
}
对于任何遇到此问题的人,它现在已在EF6中修复:
您的建议可能会起作用,但它会污染类层次结构,并违背OO.Agree的目的。这就是为什么我建议你使用TPT,正如我更新的答案所示。谢谢,我看到你添加了TPT建议。这是一个很好的建议,尽管出于性能原因,我仍然希望有一个表。没问题,我认为这是不可能的:
指定的模式无效。错误:(10,6):错误0019:类型中的每个属性名称必须是唯一的。属性名“Customer”已经定义。
我只希望Microsoft在TPH中使用类名前缀而不是顺序后缀。这将使模式更具可读性!事实证明,这是代码优先代码(仍然存在于EF6中)中的一个错误,它在生成数据库模式时生成了两个同名列。EF运行时和EF设计器实际上支持此场景。欢迎在CodePlex中投票支持这个问题:我上面提到的bug在EF6的最新版本中已经修复。EF6中的解决方案:链接已经过时。