Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Entity Framework 4 - Code First not storing inherited table separate from base table

With EF Code First CTP 4 I've created a simple project. This project consists of 2 classes, one inherited from other.

I wish to store the data in separate tables, but the default of EF 4 is to map/store these two entities in the same table.

With .ToTable(), I can change this behavior, but with this I have a side effect: when I persist a Inherited object, EF doesn't persist the common values (ex. Id) on the base class.

I'm sure I'm leaving to set some information in the mapping but do not know which.

static void Main(string[] args)
{
    Database.SetInitializer<ZooContext>(new RecreateDatabaseIfModelChanges<ZooContext>());
    using (ZooContext ctx = new ZooContext())
    {
        Mammal mam = new Mammal() ;
        mam.NumberOfLegs = 4;
        ctx.Animals.Add(mam);
        // ctx.Mammals.Add(mam)  as the same behavior
        ctx.SaveChanges();
    }
}


public class ZooContext : DbContext
{   
    public DbSet<Animal> Animals { get; set; }
    public DbSet<Mammal> Mammals { get; set; }

    protected override void OnModelCreating(System.Data.Entity.ModelConfiguration.ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Animal>().HasKey(p => p.Id).
                                    MapHierarchy().
                                    Case<Animal>(a => new { a.Id });
        modelBuilder.Entity<Animal>().HasKey(p => p.Id).
                                    MapHierarchy().
                                    Case<Mammal>(a => new { a.Id, a.NumberOfLegs }).ToTable("Mammals");

        base.OnModelCreating(modelBuilder);
    }
}

public class Animal
{
    public virtual int Id { get; set; }
}

public class Mammal : Animal
{
    public int NumberOfLegs { get; set; }
}
like image 507
Cassio Eskelsen Avatar asked Jul 28 '10 19:07

Cassio Eskelsen


1 Answers

Don't really know about CTP4, but in CTP5 this can be done using .Map(x=>x.ToTable("TableName")) here is example of what you want:

public class Mammal
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public class Animal : Mammal
{
    public int NumberOfLegs { get; set; }
}

public class ZooContext : DbContext
{
    public DbSet<Mammal> Mammals { get; set; }
    public DbSet<Animal> Animals { get; set; }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        builder.Entity<Mammal>()
            .Map<Animal>(x => x.ToTable("Animals"))
            .Map<Mammal>(x => x.ToTable("Mammals"));

        base.OnModelCreating(builder);
    }
} 

class Program
{
    static void Main()
    {
        DbDatabase.SetInitializer(new DropCreateDatabaseIfModelChanges<ZooContext>());

        using (var ents = new ZooContext())
        {
            ents.Mammals.Add(new Animal { Name = "First Mutant Animal", NumberOfLegs = 10 });
            ents.Mammals.Add(new Mammal { Name = "First Mammal" });
            ents.Mammals.Add(new Mammal { Name = "Second Mammal" });
            ents.SaveChanges();
        }
    }
}

PS: I used SqlCe 4.0 as database engine. This fails to start, if Mammal class has only Id and no other properties (Don't know why). So I added Name property base class. I'm not sure weather it is problem in CTP4, SqlCe 4.0, or I just don't know something.

Hope this helps.

like image 199
The Smallest Avatar answered Nov 15 '22 07:11

The Smallest