【问题标题】:EF5 Two level inheritance, TPT + TPH (Code first)EF5 两级继承,TPT + TPH(代码优先)
【发布时间】:2013-08-30 09:37:24
【问题描述】:

我已经使用 EF5 代码优先 TPT 实现了一个简单的继承。 我的基类是“Person”,我的继承类是“User”。表被相应地命名。

由于我的软件将被用作其他人在其之上构建的框架,我想为他们提供一个简单的工具来扩展软件而不更改数据库。我只需要获取正确的类类型,我不需要更新它。为了实现这一点,我想要一个专门用于 TPH 用户的层。开发人员将在代码中添加他们的类并插入他们标记类型的记录。

我已将“鉴别器”字段添加到用户表中,但现在尝试加载模型时出现此错误:

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

这个错误的含义还不是很清楚.. 任何人都可以提出解释/解决方案吗?

提前致谢

【问题讨论】:

    标签: c# entity-framework inheritance ef-code-first


    【解决方案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 对其进行映射。

    需要注意的重要一点是,“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 });
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-01-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多