Note that there are some explanatory texts on larger screens.

plurals
  1. POEF Code First: Migrations removing needed columns and adding unwanted ones
    primarykey
    data
    text
    <p>Note: there is a "better" iteration of this question here:</p> <p><a href="https://stackoverflow.com/questions/16274653/ef-code-first-migrations-table-per-hierarchy-bug">EF Code First migrations: Table Per Hierarchy Bug</a></p> <hr> <p>I am trying to figure out the exact steps need to take an existing database and overlay entity framework code first with a Table Per Hierarchy structure. However no matter what I do, the end result migration is "wrong".</p> <p>Here is the sample database, exact steps and output.</p> <p>Existing database structure</p> <pre><code>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 </code></pre> <p>"Reverse Engineer Code First" generates the following:</p> <pre><code> public partial class EntityContext : DbContext { static EntityContext() { Database.SetInitializer&lt;EntityContext&gt;(null); } public EntityContext() : base("Name=Test47Context") { } public DbSet&lt;A&gt; A { get; set; } public DbSet&lt;Category&gt; 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&lt;int&gt; CategoryId { get; set; } public virtual Category Category { get; set; } } public partial class Category { public Category() { this.A = new List&lt;A&gt;(); } public int Id { get; set; } public string Name { get; set; } public virtual ICollection&lt;A&gt; A { get; set; } } public class AMap : EntityTypeConfiguration&lt;A&gt; { public AMap() { // Primary Key this.HasKey(t =&gt; t.Id); // Properties this.Property(t =&gt; t.Discriminator) .IsRequired() .HasMaxLength(20); this.Property(t =&gt; t.Description) .IsRequired() .HasMaxLength(100); // Table &amp; Column Mappings this.ToTable("A"); this.Property(t =&gt; t.Id).HasColumnName("Id"); this.Property(t =&gt; t.Discriminator).HasColumnName("Discriminator"); this.Property(t =&gt; t.Description).HasColumnName("Description"); this.Property(t =&gt; t.CategoryId).HasColumnName("CategoryId"); // Relationships this.HasOptional(t =&gt; t.Category) .WithMany(t =&gt; t.A) .HasForeignKey(d =&gt; d.CategoryId); } } public class CategoryMap : EntityTypeConfiguration&lt;Category&gt; { public CategoryMap() { // Primary Key this.HasKey(t =&gt; t.Id); // Properties this.Property(t =&gt; t.Name) .IsRequired() .HasMaxLength(100); // Table &amp; Column Mappings this.ToTable("Categories"); this.Property(t =&gt; t.Id).HasColumnName("Id"); this.Property(t =&gt; t.Name).HasColumnName("Name"); } } </code></pre> <p>Implement TPH, by </p> <ul> <li>Adding <code>Derived.cs</code> inherits from <code>A.cs</code></li> <li>Moving <code>Category</code> and <code>CategoryId</code> properties from <code>A.cs</code> to <code>Derived.cs</code></li> <li>Remove <code>Discriminator</code> property from <code>A.cs</code></li> <li>In <code>AMap.cs</code> remove <code>Discriminator</code>, <code>CategoryId</code> and <code>Category</code> Foreign Key mapping.</li> <li><p>Adding TPH mapping to <code>OnModelCreating</code></p> <pre><code>public partial class EntityContext : DbContext { static EntityContext() { Database.SetInitializer&lt;EntityContext&gt;(null); } public EntityContext() : base("Name=Test47Context") { } public DbSet&lt;A&gt; A { get; set; } public DbSet&lt;Category&gt; Categories { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Configurations.Add(new AMap()); modelBuilder.Configurations.Add(new CategoryMap()); modelBuilder.Entity&lt;A&gt;() .Map&lt;Derived&gt;(x =&gt; 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&lt;int&gt; CategoryId { get; set; } public virtual Category Category { get; set; } } public partial class Category { public Category() { this.A = new List&lt;A&gt;(); } public int Id { get; set; } public string Name { get; set; } public virtual ICollection&lt;A&gt; A { get; set; } } public class AMap : EntityTypeConfiguration&lt;A&gt; { public AMap() { // Primary Key this.HasKey(t =&gt; t.Id); this.Property(t =&gt; t.Description) .IsRequired() .HasMaxLength(100); // Table &amp; Column Mappings this.ToTable("A"); this.Property(t =&gt; t.Id).HasColumnName("Id"); this.Property(t =&gt; t.Description).HasColumnName("Description"); } } public class CategoryMap : EntityTypeConfiguration&lt;Category&gt; { public CategoryMap() { // Primary Key this.HasKey(t =&gt; t.Id); // Properties this.Property(t =&gt; t.Name) .IsRequired() .HasMaxLength(100); // Table &amp; Column Mappings this.ToTable("Categories"); this.Property(t =&gt; t.Id).HasColumnName("Id"); this.Property(t =&gt; t.Name).HasColumnName("Name"); } } </code></pre></li> </ul> <p>"Add-migration TPH" generates the following</p> <pre><code>public partial class TPH : DbMigration { public override void Up() { AddColumn("dbo.A", "Category_Id", c =&gt; 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 =&gt; c.String(nullable: false, maxLength: 20)); DropIndex("dbo.A", new[] { "Category_Id" }); DropForeignKey("dbo.A", "Category_Id", "dbo.Categories"); DropColumn("dbo.A", "Category_Id"); } } </code></pre> <ul> <li>Why does it drop the <code>Discriminator</code> column instead of just altering it to <code>nvarchar(128)</code>?</li> <li>Why doesn't just use the existing <code>CategoryId</code> column instead of adding <code>Category_Id</code>?</li> </ul>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload