繁体   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