1
Vote

Better error message when trying to configure nav prop to belong to two relationships.

description

hi i have been using entity framework 5 code first in an mvc web application and it was working fine but recently i add a few more models to it as the app is growing but when i try to issue add-migration command in the package manager console in VS 2012 i get this vexing exception "Object reference not set to an instance of an object" i even tried switching to version 6 but then version 6 does not see my data context, but what am i missing as i have been stuck in this for many days now. Here is my stacktrace

I found a simpler repro on:
http://www.mycsharp.de/wbb2/thread.php?threadid=108954
    public class Person
    {
        public int PersonID { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }

        public virtual ICollection<Meeting> Meeting { get; set; }
    }

    public class Meeting
    {
        public int MeetingID { get; set; }

        [ForeignKey("Customer")]
        public int CustomerID { get; set; }

        public virtual Person Customer { get; set; }

        [ForeignKey("SalesAgent")]
        public int SalesAgentID { get; set; }

        public virtual Person SalesAgent { get; set; }
    }


    public class Context : DbContext
    {
        public DbSet<Person> People { get; set; }
        public DbSet<Meeting> Meetings { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Meeting>().HasRequired(m => m.Customer).WithMany(p => p.Meeting);
            modelBuilder.Entity<Meeting>().HasRequired(m => m.SalesAgent).WithMany(p => p.Meeting);
        }
    }
System.NullReferenceException: Object reference not set to an instance of an object.
at System.Data.Entity.ModelConfiguration.Configuration.Types.EntityTypeConfiguration.Configure(EdmEntityType entityType, EdmModel model)
at System.Data.Entity.ModelConfiguration.Configuration.ModelConfiguration.ConfigureEntities(EdmModel model)
at System.Data.Entity.DbModelBuilder.Build(DbProviderManifest providerManifest, DbProviderInfo providerInfo)
at System.Data.Entity.DbModelBuilder.Build(DbConnection providerConnection)
at System.Data.Entity.Infrastructure.EdmxWriter.WriteEdmx(DbContext context, XmlWriter writer)
at System.Data.Entity.Migrations.Extensions.DbContextExtensions.<>c__DisplayClass1.<GetModel>b__0(XmlWriter w)
at System.Data.Entity.Migrations.Extensions.DbContextExtensions.GetModel(Action1 writeXml)
at System.Data.Entity.Migrations.Extensions.DbContextExtensions.GetModel(DbContext context)
at System.Data.Entity.Migrations.DbMigrator..ctor(DbMigrationsConfiguration configuration, DbContext usersContext)
at System.Data.Entity.Migrations.DbMigrator..ctor(DbMigrationsConfiguration configuration)
at System.Data.Entity.Migrations.Design.ToolingFacade.BaseRunner.GetMigrator()
at System.Data.Entity.Migrations.Design.ToolingFacade.GetPendingMigrationsRunner.RunCore()
at System.Data.Entity.Migrations.Design.ToolingFacade.BaseRunner.Run()
Object reference not set to an instance of an object.
``

file attachments

comments

Cizaphil wrote Aug 8, 2013 at 10:34 PM

I have added the model that am using.

moozzyk wrote Sep 12, 2013 at 11:28 PM

In EF5 the NRE exception is thrown because there is a bug where we pass a PropertyInfo for the foreign key property instead of the PropertyInfo for the navigation property. As a result we look up the configuration for the entity type but the "entity type" we have is actually a primitive type (the type of the foreign key property - e.g. int) so the look up returns null which we try to dot on which throws the NRE.

In EF6 the code was changed and we no longer have the issue with NRE. However we now see this exception (after an Assert which is not related to this issue - see 1582):
Unhandled Exception: System.Data.Entity.Core.MetadataException: Schema specified
 is not valid. Errors: The relationship 'NRERepro_EF6.Meeting_Customer' was not
loaded because the type 'NRERepro_EF6.Person' is not available.
   at System.Data.Entity.Core.Metadata.Edm.CodeFirstOSpaceTypeFactory.LogError(S
tring errorMessage, EdmType relatedType) in c:\Source\entityframework\src\Entity
Framework\Core\Metadata\ObjectLayer\CodeFirstOSpaceTypeFactory.cs:line 27
This happens because of how the model is setup. When we configure the inverse navigation property for the second navigation property (which has already been configured when the first navigation property was configured) we remove the association type that was created when configuring the first navigation property but in this case the type should not be removed, rather than the relationship should be turned into an independent association. I tried a naïve approach for not removing the association type if there are multiple navigation properties pointing to the same entity type but it did not work for entities with self references (like the ArubaPerson entity type used in the tests).

Another interesting datapoint here is why the model was configured this way. I think the user wanted to "collapse" dependent entities into just one collection even though they relations are actually different. However it is not possible to map multiple navigation properties to one inverse navigation property. It becomes even clearer if you try configure the relationship from the other end like this:
modelBuilder.Entity<Person>().HasMany(p => p.Meeting).WithRequired(m => m.Customer).WillCascadeOnDelete(false);
modelBuilder.Entity<Person>().HasMany(p => p.Meeting).WithRequired(m => m.SalesAgent).WillCascadeOnDelete(false);
In this case the second configuration just overwrites the first one. In the configuration from the repro since we configure from the other end we create a separate configuration for each navigation property on the dependent and therefore they did not overwrite one another.

From the user perspective the fix is to change the model so that the principal has two navigation properties that would be configured as inverse navigation properties for the corresponding navigation properties on the dependent.

RoMiller wrote Sep 16, 2013 at 7:19 PM

EF Team Triage: Per Pawel's last comment this is an error condition because Person.Meeting can't be part of two separate relationships. We should improve the error message though.
When fixing this issue we should also consider the situation where you configure the relationships starting with Person. In this case we currently apply the 'last config wins' rule so it's not an error condition.

RoMiller wrote Dec 12, 2013 at 9:35 PM

EF Team Triage: Moving issues with Impact set to Low out of the 6.1.0 release as we only have time to address High and Medium issues in this release. We will re-triage these issues for future releases.

This does not exclude someone outside of the Microsoft EF team from contributing the change/fix in 6.1.0.