2013-08-30 108 views
0

我已經實現了使用EF5代碼優先TPT的簡單繼承。 我的基類是「Person」,我的繼承類是「User」。表格被相應地命名。EF5兩級繼承,TPT + TPH(代碼優先)

由於這一事實,我的軟件是會被重用爲其他人建立在它之上的一個框架,我想給他們一個簡單的工具,而不更改數據庫擴展軟件。我只需要獲取正確的類類型,我不需要更新它。爲了實現這一點,我想爲TPH用戶提供專門的圖層。開發人員將在代碼中添加他們的類並插入標記類型的記錄。

我已經添加到用戶表中的「鑑別」領域,但現在我得到這個錯誤試圖加載模型:

Error 3032: Problem in mapping fragments : mapped to the same rows in table 

它並不真正清楚什麼錯誤意味着.. 任何人都可以爲此提出一個解釋/解決方案?

在此先感謝

回答

1

一些挖後,我發現,它可能確實,我不知道,因爲該版本,但它的工作原理就像一個EF5魅力。

上述錯誤的解決方案是使用Fluent API手動映射關係。 的TPT層需要:兩個表類

  • 繼承關係之間的兩個
  • 相同的主密鑰,和用於遺傳表型上的主鍵的外鍵。

下面是類定義:

[Table("Persons", Schema="MySchema")] 
public partial class Person 
{ 
    public int PersonId { get; set; } 
    public string Name { get; set; } 
} 

[Table("Users", Schema = "MySchema")] 
partial class User : Person 
{ 
} 

的TPH層似乎不工作只是添加「鑑別」字段。我找到的解決方案是:

  • 將「UserType」字段添加到數據庫。
  • 使用Fluent API進行映射。

一個重要的注意,使的是,「用戶類型」字段不能包含在類定義或者你會得到上述錯誤。

public class CustomUser : User 
{ 
} 

中的DbContext類中,在OnModelCreating覆蓋:

modelBuilder.Entity<User>().Map<User>(m => 
    { 
     m.ToTable("Users"); 
     m.Requires("UserType").HasValue("User"); 
    }).Map<CustomUser>(m => 
    { 
     m.Requires("UserType").HasValue("CustomUser"); 
    }); 

最後,有這樣的代碼的DbContext是不是真的可重複使用,從而爲以下我搬到它EntityTypeConfiguration類中:

public class CustomUserConfiguration : EntityTypeConfiguration<CustomUser> 
{ 
    public CustomUserConfiguration() 
    { 
     Map<CustomUser>(m => m.Requires("UserType").HasValue("CustomUser")); 
    } 
} 

的的DbContext現在可以用一個小的反射來加載所有的EntityTypeConfiguration類

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
{ 
    MethodInfo addMethod = typeof(ConfigurationRegistrar).GetMethods().Single(m => m.Name == "Add" && m.GetGenericArguments().Any(a => a.Name == "TEntityType")); 
    IList<Assembly> assemblies = AppDomain.CurrentDomain.GetAssemblies().Where(a => !a.GetName().Name.StartsWith("System") && !a.GetName().Name.StartsWith("Microsoft")).ToList(); 
    foreach (Assembly assembly in assemblies) 
    { 
     IList<Type> types = assembly.GetTypes().Where(t => t.BaseType != null && t.BaseType.IsGenericType && t.BaseType.GetGenericTypeDefinition() == typeof(EntityTypeConfiguration<>)).ToList(); 
     foreach (Type type in types) 
     { 
      Type entityType = type.BaseType.GetGenericArguments().Single(); 
      object entityConfig = assembly.CreateInstance(type.FullName); 
      addMethod.MakeGenericMethod(entityType).Invoke(modelBuilder.Configurations, new object[] { entityConfig }); 
     } 
    } 
}