Question

I have several classes that I need to derive from a common base class which holds an Id. Ignoring the all but one of these for the moment, let's say we have:

public class MyBase {
   [Key]
   public int Id { get; set; } 
}
public class MyName : MyBase {
   public string Name { get; set; }
}

my context (DataContext) looks like this:

public DbSet<MyName>MyNames { get; set; }

// to avoid having EF make a MyBases table and instead map 
// MyBase.Id into MyNames and my other derived classes I do this ...

protected override void OnModelCreating((DbModelBuilder modelBuilder) {
   modelBuilder.Entity<MyBase>()
            .Property(c => c.Id)
            .HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);

   modelBuilder.Entity<MyName>()
            .Map(m => {
                    m.MapInheritedProperties();
                    m.ToTable("MyNames");
                });
}

The resulting DB, when I Enable-Migrations, Add-Migration Initial, and Update-Database is that I get no table called MyBases, but instead I get the Id column in MyNames

   dbo.MyNames
   -----------
   Id (PK, int, not null)
   Name (nvarchar(max), null)

So far so good, all of that compiles and builds, and then I test it using something like the following:

   using ( DataContext dc = new DataContext()) {
      var jj = new MyName { Name = "Janice Joplin" };
      dc.MyNames.Add(jj);
      dc.SaveChanges();

      var jh = new MyName { Name = "Jimmy Hendrix" };
      dc.MyNames.Add(jh);
      dc.SaveChanges();
   }

This works the first time (Janice is added with Id = 0) but not the second ... Jimmy gets a DUPLICATE KEY exception. Note (for full disclosure) I'm actually creating the jj and jh objects in another part of my code, then passing them into this method (above) as MyBase objects, then casting them back to MyName objects if that's what they are. I hope that isn't a problem.

I guess if everything were in one table, the Id could be marked as Identity and @@IDENTITY could be used to assign the object Id value. Perhaps I will need to make a MyBases table after all, and create that record first, then duplicate the Id into the derived tables in a transaction. What's the best approach for this?

Any help for this EF6 CodeFirst newbie would be appreciated. THANKS.

Was it helpful?

Solution

I remember when I used to do EF I would create a table with Identity and in the class I would attribute the id column with

[DatabaseGenerated(DatabaseGeneratedOption.Identity)]

so I am assuming that your code should be

   modelBuilder.Entity<MyBase>()
        .Property(c => c.Id)
        .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

OTHER TIPS

I believe the problem lies in the fact you are using EF6 Code First Migrations. When you are doing so you need to seed your DB using the .AddOrUpdate() method. This Stack Overflow Question covers it.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top