经过一番挖掘,我发现确实有可能,我不确定从哪个版本开始,但它在 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 });
}
}
}