我使用EF5代码优先TPT实现了一个简单的继承。 我的基类是“Person”,我继承的类是“User”。表格相应命名。
由于我的软件将被重新用作其他人构建的框架,我想给他们一个简单的工具来扩展软件而不需要更改数据库。我只需要获取正确的类类型,我不需要更新它。为了实现这一点,我想为TPH用户提供一个专门的层。开发人员将在代码中添加他们的类,并插入标记类型的记录。
我已将“Discriminator”字段添加到Users表中,但现在我在尝试加载模型时遇到此错误:
Error 3032: Problem in mapping fragments : mapped to the same rows in table
错误意味着什么并不是很清楚。 有人可以建议解释/解决方案吗?
提前致谢
答案 0 :(得分: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层似乎只是添加“Discriminator”字段。我找到的解决方案是:
要做的一个重要注意事项是“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 });
}
}
}