注意:这里有一个“更好”的问题迭代:
EF Code First migrations: Table Per Hierarchy Bug
我试图找出首先采用Table Per Hierarchy结构获取现有数据库和覆盖实体框架代码的确切步骤。但无论我做什么,最终结果迁移都是“错误的”。
以下是示例数据库,确切的步骤和输出。
现有数据库结构
CREATE TABLE [dbo].[Categories](
[Id] [int] IDENTITY(1,1) NOT NULL Primary Key,
[Name] [nvarchar](100) NOT NULL,
)
GO
CREATE TABLE [dbo].[A](
[Id] [int] IDENTITY(1,1) NOT NULL Primary Key,
[Discriminator] [nvarchar](20) NOT NULL,
[Description] [nvarchar](100) NOT NULL,
[CategoryId] [int] NULL
)GO
ALTER TABLE [dbo].[A]
WITH CHECK ADD CONSTRAINT [FK_dbo.A_dbo.Categories_CategoryId]
FOREIGN KEY([CategoryId])
REFERENCES [dbo].[Categories] ([Id])
GO
ALTER TABLE [dbo].[A]
CHECK CONSTRAINT [FK_dbo.A_dbo.Categories_CategoryId]
GO
“逆向工程师代码优先”生成以下内容:
public partial class EntityContext : DbContext {
static EntityContext() {
Database.SetInitializer<EntityContext>(null);
}
public EntityContext()
: base("Name=Test47Context") {
}
public DbSet<A> A { get; set; }
public DbSet<Category> Categories { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder) {
modelBuilder.Configurations.Add(new AMap());
modelBuilder.Configurations.Add(new CategoryMap());
}
}
public partial class A {
public int Id { get; set; }
public string Discriminator { get; set; }
public string Description { get; set; }
public Nullable<int> CategoryId { get; set; }
public virtual Category Category { get; set; }
}
public partial class Category {
public Category() {
this.A = new List<A>();
}
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<A> A { get; set; }
}
public class AMap : EntityTypeConfiguration<A> {
public AMap() {
// Primary Key
this.HasKey(t => t.Id);
// Properties
this.Property(t => t.Discriminator)
.IsRequired()
.HasMaxLength(20);
this.Property(t => t.Description)
.IsRequired()
.HasMaxLength(100);
// Table & Column Mappings
this.ToTable("A");
this.Property(t => t.Id).HasColumnName("Id");
this.Property(t => t.Discriminator).HasColumnName("Discriminator");
this.Property(t => t.Description).HasColumnName("Description");
this.Property(t => t.CategoryId).HasColumnName("CategoryId");
// Relationships
this.HasOptional(t => t.Category)
.WithMany(t => t.A)
.HasForeignKey(d => d.CategoryId);
}
}
public class CategoryMap : EntityTypeConfiguration<Category> {
public CategoryMap() {
// Primary Key
this.HasKey(t => t.Id);
// Properties
this.Property(t => t.Name)
.IsRequired()
.HasMaxLength(100);
// Table & Column Mappings
this.ToTable("Categories");
this.Property(t => t.Id).HasColumnName("Id");
this.Property(t => t.Name).HasColumnName("Name");
}
}
通过
实施TPHDerived.cs
A.cs
个继承
Category
和CategoryId
属性从A.cs
移至Derived.cs
Discriminator
A.cs
媒体资源
AMap.cs
移除Discriminator
,CategoryId
和Category
外键映射。将TPH映射添加到OnModelCreating
public partial class EntityContext : DbContext {
static EntityContext() {
Database.SetInitializer<EntityContext>(null);
}
public EntityContext()
: base("Name=Test47Context") {
}
public DbSet<A> A { get; set; }
public DbSet<Category> Categories { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder) {
modelBuilder.Configurations.Add(new AMap());
modelBuilder.Configurations.Add(new CategoryMap());
modelBuilder.Entity<A>()
.Map<Derived>(x => x.Requires("Discriminator").HasValue("Derived"));
}
}
public partial class A {
public int Id { get; set; }
public string Description { get; set; }
}
public class Derived : A {
public Nullable<int> CategoryId { get; set; }
public virtual Category Category { get; set; }
}
public partial class Category {
public Category() {
this.A = new List<A>();
}
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<A> A { get; set; }
}
public class AMap : EntityTypeConfiguration<A> {
public AMap() {
// Primary Key
this.HasKey(t => t.Id);
this.Property(t => t.Description)
.IsRequired()
.HasMaxLength(100);
// Table & Column Mappings
this.ToTable("A");
this.Property(t => t.Id).HasColumnName("Id");
this.Property(t => t.Description).HasColumnName("Description");
}
}
public class CategoryMap : EntityTypeConfiguration<Category> {
public CategoryMap() {
// Primary Key
this.HasKey(t => t.Id);
// Properties
this.Property(t => t.Name)
.IsRequired()
.HasMaxLength(100);
// Table & Column Mappings
this.ToTable("Categories");
this.Property(t => t.Id).HasColumnName("Id");
this.Property(t => t.Name).HasColumnName("Name");
}
}
“添加迁移TPH”生成以下内容
public partial class TPH : DbMigration
{
public override void Up()
{
AddColumn("dbo.A", "Category_Id", c => c.Int());
AddForeignKey("dbo.A", "Category_Id", "dbo.Categories", "Id");
CreateIndex("dbo.A", "Category_Id");
DropColumn("dbo.A", "Discriminator");
}
public override void Down()
{
AddColumn("dbo.A", "Discriminator", c => c.String(nullable: false, maxLength: 20));
DropIndex("dbo.A", new[] { "Category_Id" });
DropForeignKey("dbo.A", "Category_Id", "dbo.Categories");
DropColumn("dbo.A", "Category_Id");
}
}
Discriminator
列而不是仅将其更改为nvarchar(128)
?CategoryId
列而不是添加Category_Id
?