[英]Entity Framework: TPC MapInheritedProperties model super class properties
摘要 :在Entity Framework中,我使用TPC創建從同一基類派生的兩個類。 在流暢的API中,我映射了繼承的屬性,但是如何對基類的屬性建模?
更廣泛的描述在Entity Framework中,我有一個類Child,和兩種孩子:Boy和Girl。 男孩和女孩都來自兒童:
public class Child
{
public int Id {get; set;}
public string Name {get; set;}
}
public class Boy : Child
{
public string SomeBoyishProperty {get; set;}
}
public class Girl : Child
{
public string SomeGirlyProperty {get; set;}
}
我想要一個帶有男孩的表和一個帶有女孩的表,每個表還具有Child屬性。
public class MyDbContext : DbContext
{
public DbSet<Boy> Boys {get; set;}
public DbSet<Girl> Girls {get; set;
}
從幾個來源,例如,我了解到這被稱為TPC:每個具體類的表,我應該在OnModelCreating中使用MapInheritedProperties
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// model the properties of the base class, for instance set max length
modelBuilder.Entity<Child>()
.Property(p => p.Name).IsRequired().HasMaxLength(12);
// Model Daughter:
modelBuilder.Entity<Daughter>()
.Map(m =>
{
m.MapInheritedProperties();
m.ToTable("Daughters");
})
.Property(p => p.SomeGirlyProperty).IsOptional().HasMaxLength(13);
// model Boy
modelBuilder.Entity<Son>()
.Map(m =>
{
m.MapInheritedProperties();
m.ToTable("Sons");
})
.Property(p => p.SomeBoyishProperty).IsOptional().HasMaxLength(14);
}
在SaveChanges期間,我收到一個InvlidOperationException異常,指示主鍵不是唯一的。 刪除構建Child的部件可以解決此問題。
如何構建子級屬性,而不必在“女孩”屬性和“男孩”屬性中再次執行此操作?
簡短答案:
如果你希望你的代碼工作,刪除任何引用Child
模型中的配置實體。 只要EF知道Child
的實體將執行以下規則:不能有型的2個實體Child
或2個實體繼承Child
與內存中的同PK。 您可以看到錯誤告訴您實體成功保存的位置; 但是當EF拉出新ID時,它發現兩者具有相同的ID。
長答案
去掉
modelBuilder.Entity<Child>()
.Property(p => p.Name).IsRequired().HasMaxLength(12);
相反,這就是您的OnModelCreating
方法的外觀。
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// Model Daughter:
var girlEntity = modelBuilder.Entity<Girl>();
girlEntity.Map(m =>
{
m.MapInheritedProperties();
m.ToTable("Daughters");
});
girlEntity.Property(p => p.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
girlEntity.Property(p => p.Name).IsRequired().HasMaxLength(12);
girlEntity.Property(p => p.SomeGirlyProperty).IsOptional().HasMaxLength(13);
// model Boy
var boyEntity = modelBuilder.Entity<Boy>();
boyEntity.Map(m =>
{
m.MapInheritedProperties();
m.ToTable("Sons");
});
boyEntity.Property(p => p.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
boyEntity.Property(p => p.Name).IsRequired().HasMaxLength(12);
boyEntity.Property(p => p.SomeBoyishProperty).IsOptional().HasMaxLength(14);
}
如果您不希望在配置中重復配置,則可以在基類上使用DataAnnotations
屬性來強制使用必需的名稱。
您還需要強制在數據庫中自動生成Id
屬性。 在流利的API中使用Map
方法時,按慣例不會發生這種情況。 您可以看到我添加了流利的調用,以實現在“ Girl
和“ Boy
貼圖中的實現。
希望這可以幫助。
我重新設計了Arturo的解決方案。 此解決方案太長,無法描述為評論。 所以Arturo:感謝您給我的想法 。 起首!
Arturo建議使用數據注釋。 我不想使用該方法的原因是,該類的建模不必與某個數據庫表示相對應。 我有點假設,但是如果我希望男孩名的最大長度小於女孩名的最大長度,那么數據注釋將無濟於事。
此外,使用流利的API還需要做一些事情。 例如,您不能說使用DataAnnotations在數據庫中System.DateTime
具有DateTime2
格式。
如果您還沒有猜到:我的問題描述得到了高度簡化。 這三個類都有很多屬性,需要大量流利的API配置
Arturo的言論幫助我實現了以下解決方案:
internal class ChildConfig<T> : EntityTypeConfiguration<T> where T : Child
{
public ChildConfig(...)
{
// configure all Child properties
this.Property(p => p.Name)....
}
}
internal class BoyConfig : ChildConfig<Boy>
{
public BoyConfig(...) : base (...)
{
// the base class will configure the Child properties
// configure the Boy properties here
this.Property(p => p.SomeBoyishProperty)...
}
}
在MyDbContext中:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new BoyConfig(...));
modelBuilder.Configuration.Add(new GirlConfig(...));
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.