locked
EF 4.1 TPT Bug? RRS feed

  • Question

  • Something that used to work in CTP5 no longer works in the RTW.  I'm trying to use TPT to model a some tables, and also have a related class have a property to one of the descendant classes.  Here's a dummy model and classes which reproduces the error.  I am trying to generate a database to sql express on my machine.

        public class MyContext : DbContext
        {
            public DbSet<Child1> Child1 { getset; }
            public DbSet<Child2> Child2 { getset; }
            public DbSet<RelatedClass> RelatedClass { getset; }
     
     
            public MyContext()
            {
                this.Configuration.AutoDetectChangesEnabled = true;
                this.Configuration.LazyLoadingEnabled = true;
                this.Configuration.ValidateOnSaveEnabled = true;
            }
     
            protected override void OnModelCreating(DbModelBuilder modelBuilder)
            {
                base.OnModelCreating(modelBuilder);
     
                modelBuilder.Configurations.Add(new BaseClassConfig());
     
                modelBuilder.Entity<Child1>().ToTable("Child1");
                modelBuilder.Entity<Child2>().ToTable("Child2");
            }
     
        }
     
     
        public abstract class BaseClass
        {
            public Guid BaseId { getset; }
            public string BaseName { getset; }
        }
     
        public class BaseClassConfig : EntityTypeConfiguration<BaseClass>
        {
            public BaseClassConfig()
            {
                HasKey<Guid>(p => p.BaseId);
                Property(p => p.BaseName).IsRequired().HasMaxLength(10);
            }
        }
     
        public class Child1 : BaseClass
        {
            public string Child1Field { getset; }
        }
     
        public class Child1Config : EntityTypeConfiguration<Child1>
        {
            public Child1Config()
            {
                Property(p => p.Child1Field).IsRequired().HasMaxLength(10);
                //ToTable("Child1s");
            }
        }
     
        public class Child2 : BaseClass
        {
            public string Child2Field { getset; }
            public virtual Child1 Child1 { getset; }
            public virtual ICollection<RelatedClass> RelatedClass { getset; }
        }
     
        public class Child2Config : EntityTypeConfiguration<Child2>
        {
            public Child2Config()
            {
                Property(p => p.Child2Field).IsRequired().HasMaxLength(10);
                HasRequired(p => p.Child1);
                HasMany(p => p.RelatedClass);
                //ToTable("Child2s");
            }
        }

     

    The error I get when I run is: 

    Error retrieving values from ObjectStateEntry

    (6,10) : error 3004: Problem in mapping fragments starting at lines 6, 12:No mapping specified for properties BaseClass.BaseName in Set BaseClasses.
    An Entity with Key (PK) will not round-trip when:
      Entity is type [EFBug.Child1]

    (6,10) : error 3004: Problem in mapping fragments starting at lines 6, 12:No mapping specified for properties BaseClass.BaseName in Set BaseClasses.
    An Entity with Key (PK) will not round-trip when:
      Entity is type [EFBug.Child2]

    I've tried switching where the ToTable is called, I've tried using the Map method within the Configuration class.  Sometimes it generates one big BaseClass table with ALL the properties of ALL 3 classes in it, but that's not what I want.

    Is this a bug or am I doing something wrong?

    Friday, March 18, 2011 5:10 PM

Answers

  • Hi Rick,

    Unlike CTP5, in EF 4.1 RC you need to explicitly specify a table name for your abstract base class when configuring a TPT mapping to get over this exception. Like the following code:

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {      
      modelBuilder.Entity<BaseClass>().ToTable("BaseClass");
      modelBuilder.Entity<Child1>().ToTable("Child1");
      modelBuilder.Entity<Child2>().ToTable("Child2");     
    }

    And yes, I think it's a bug in RC and not a change of behaviour since if you drop the abstract keyword from your BaseClass then you do not need the modelBuilder.Entity<BaseClass>().ToTable("BaseClass"); line in your fluent API code and it will work just fine.

     

    • Proposed as answer by Morteza Manavi Friday, March 18, 2011 7:09 PM
    • Marked as answer by Rick Langel Tuesday, March 22, 2011 2:27 PM
    Friday, March 18, 2011 6:20 PM

All replies

  • Clarification:  I realize I forgot to add the configurations for the concrete classes.  I add that and it still gives the same error.
    Friday, March 18, 2011 6:00 PM
  • Hi Rick,

    Unlike CTP5, in EF 4.1 RC you need to explicitly specify a table name for your abstract base class when configuring a TPT mapping to get over this exception. Like the following code:

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {      
      modelBuilder.Entity<BaseClass>().ToTable("BaseClass");
      modelBuilder.Entity<Child1>().ToTable("Child1");
      modelBuilder.Entity<Child2>().ToTable("Child2");     
    }

    And yes, I think it's a bug in RC and not a change of behaviour since if you drop the abstract keyword from your BaseClass then you do not need the modelBuilder.Entity<BaseClass>().ToTable("BaseClass"); line in your fluent API code and it will work just fine.

     

    • Proposed as answer by Morteza Manavi Friday, March 18, 2011 7:09 PM
    • Marked as answer by Rick Langel Tuesday, March 22, 2011 2:27 PM
    Friday, March 18, 2011 6:20 PM
  • Thanks, Morteza.  I tried every variation of where to set the ToTable property, and it didn't work until I did as you described and removed the "abstract" clause from the baseclass definition.  Definitely different from the CTP.
    Tuesday, March 22, 2011 2:28 PM
  • Thanks so much for this answer. I was pulling my hair out after upgrading to EF 4.1 RC and running into the same issue with my TPT configuration. For other people searching for this issue my error codes were different than the OP's. Address is my abstract class in this case. Adding the .ToTable("Addresses") in the model builder got everything working again.

    Exception Details: System.Data.MetadataException: Schema specified is not valid. Errors:
    (133,6) : error 0040: Type Address is not defined in namespace CodeFirstDatabaseSchema (Alias=Self).
    (286,8) : error 0100: The referenced EntitySet Address for End Address could not be found in the containing EntityContainer.

    Saturday, March 26, 2011 6:56 PM