簡體   English   中英

EF5兩級繼承,TPT + TPH(代碼優先)

[英]EF5 Two level inheritance, TPT + TPH (Code first)

我已經使用EF5代碼優先的TPT實現了簡單的繼承。 我的基類是“人”,而繼承的類是“用戶”。 表被相應地命名。

由於我的軟件將被復用為其他人在其上構建的框架,因此,我想給他們一個簡單的工具來擴展軟件而無需更改數據庫。 我只需要獲取正確的類類型,就不需要更新它。 為了實現這一目標,我希望為具有TPH的用戶提供專門的層。 開發人員將在代碼中添加其類,並插入標記該類型的記錄。

我已經在“用戶”表中添加了“ Discriminator”字段,但是現在我在嘗試加載模型時遇到此錯誤:

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

目前尚不清楚該錯誤是什么意思。有人可以提出解釋/解決方案嗎?

提前致謝

經過一番挖掘,我發現確實有可能,我不確定從哪個版本開始,但是它在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
{
}

僅添加“ Discriminator”字段,TPH層似乎不起作用。 我找到的解決方案是:

  • 向數據庫添加“ UserType”字段。
  • 使用Fluent API對其進行映射。

需要注意的重要一點是,“ UserType”字段不能包含在類定義中,否則您將得到上面的錯誤。

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 });
        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM