8

Closed

Code First: TPC with two abstract base classes fails [FixedIn6.1.0-alpha1] [AffectedLastRTM]

description

The following code fails to build a model because there are two abstract base classes before the first concrete class. Removing BillingDetailBase causes the model to be successfully built.
public class MyContext : DbContext
{
  public DbSet<User> Users { get; set; }

  protected override void OnModelCreating(DbModelBuilder modelBuilder)
  {
    modelBuilder.Entity<BankAccount>().Map(m => 
        { 
            m.ToTable("BankAccounts"); 
           m.MapInheritedProperties(); 
        });

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

public abstract class BillingDetailBase
{
  public Int32 Id { get; set; }
}

public abstract class BillingDetail : BillingDetailBase
{
  public string Owner { get; set; }
}

public class User
{
  public int UserId { get; set; }
  public virtual BillingDetailBase BillingDetail { get; set; }
}

public class BankAccount : BillingDetail
{
  public string BankName { get; set; }
  public string Swift { get; set; }
}

public class CreditCard : BillingDetail
{
  public int CardType { get; set; }
  public string ExpiryMonth { get; set; }
  public string ExpiryYear { get; set; }
}
The error that gets generated is:
System.Data.Entity.ModelConfiguration.ModelValidationException: One or more validation errors were detected during model generation:

\tBillingDetailBase: : The referenced EntitySet 'BillingDetailBase' for End 'BillingDetailBase' could not be found in the containing EntityContainer.

   at System.Data.Entity.Core.Metadata.Edm.EdmModel.Validate()
   at System.Data.Entity.DbModelBuilder.Build(DbProviderManifest providerManifest, DbProviderInfo providerInfo)
   at System.Data.Entity.DbModelBuilder.Build(DbConnection providerConnection)
   at System.Data.Entity.Internal.LazyInternalContext.CreateModel(LazyInternalContext internalContext)
   at System.Data.Entity.Internal.RetryLazy`2.GetValue(TInput input)
   at System.Data.Entity.Internal.LazyInternalContext.InitializeContext()
   at System.Data.Entity.Internal.LazyInternalContext.get_CodeFirstModel()
   at System.Data.Entity.Infrastructure.EdmxWriter.WriteEdmx(DbContext context, XmlWriter writer)
   --- End of inner exception stack trace ---
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
   at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at System.RuntimeType.InvokeMember(String name, BindingFlags bindingFlags, Binder binder, Object target, Object[] providedArgs, ParameterModifier[] modifiers, CultureInfo culture, String[] namedParams)
   at Microsoft.DbContextPackage.Handlers.ViewContextHandler.ViewContext(MenuCommand menuCommand, Object context, Type systemContextType)
Closed Nov 22, 2013 at 6:52 PM by Mugdhak
Verified fixed. The original issue and the slightly different version that Maurycy had, are both fixed.

comments

RoMiller wrote Apr 4, 2013 at 4:27 PM

EF Team Triage: We agree that this should be fixed. We haven't seen many people hit this and the workaround is to avoid two abstract base classes. Given that and considering it's a complex area of the code base to change we are going to address this post EF6.

erictosi wrote Oct 11, 2013 at 2:00 PM

Having muliple abstract class in inheritance hierarchy is not so rare.

We encoutered same problem and our classes are generated from an UML model.
Is there any workaround for this ?

tarr11 wrote Oct 23, 2013 at 11:33 PM

Just tried to upgrade a project that hits this bug. Showstopper for us, we can't upgrade without changing lots of code. Pretty disappointing to break this existing behavior.

ajcvickers wrote Oct 25, 2013 at 4:08 PM

Note for triage: Last comment indicates that this is a regression.

glennc wrote Oct 25, 2013 at 6:09 PM

EF Team Triage: verify if this is a regression from EF5 as part of fixing.

gjsduarte wrote Oct 27, 2013 at 1:42 PM

I also confirm the issue after the upgrade to EF6.
Working good in EF5.

AndrewPeters wrote Nov 1, 2013 at 10:57 PM

Looks like this was fixed between 6.0.0-beta1 and 6.0.0-rc1.

maumar wrote Nov 4, 2013 at 5:31 PM

Slightly modified, still Repros with today's nightly:
namespace Verify1770
{
    using System.Collections.Generic;
    using System.Data.Entity;
    using System.Linq;

    public class MyContext : DbContext
    {
        public DbSet<MyBase> Entities { get; set; }


        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Foo>().Map(m =>
            {
                m.ToTable("Foo");
                m.MapInheritedProperties();
            });

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

    public abstract class MyBase
    {
        public int Id { get; set; }
        public ICollection<Foobar> Foobars { get; set; }
    }

    public abstract class MyBase2 : MyBase
    {
    }

    public class Foo : MyBase2
    {
        public string Fo { get; set; }
    }

    public class Bar : MyBase2
    {
        public string Ba { get; set; }
    }

    public class Foobar
    {
        public int Id { get; set; }
    }


    class Program
    {
        static void Main(string[] args)
        {
            using (var ctx = new MyContext())
            {
                ctx.Entities.ToList();
            }
        }
    }
}

AndrewPeters wrote Nov 4, 2013 at 9:19 PM

Sending back for re-triage because the new repro is not a regression. It is also quite an unusual model in that the Foobar table has an FK that points to two PK columns in different tables. i.e. It is not possible to have a DB FK constraint for this relationship.

divega wrote Nov 5, 2013 at 7:40 PM

We looked at this in triage and decided to punt to 6.1 since it is not a regression. From looking at the code and the exception this does seem to be a scenario supported by the runtime. We do support associations not backed by FK constrains in the database.

ajcvickers wrote Nov 12, 2013 at 6:15 PM

Pnotenb wrote Nov 25, 2013 at 2:32 PM

We also have this regression.
Worked in EF5 not in EF6 .0.1. => There still is some regression!