JaxFirehart
JaxFirehart

Reputation: 61

Null reference exception in Entity Framework when adding new object to DbContext

When adding a new object to my DbContext, I am getting a nullreferenceexception thrown from inside of Entity Framework.

Stack Trace:

at System.Data.Entity.Core.Objects.DataClasses.RelatedEnd.GetOtherEndOfRelationship(IEntityWrapper wrappedEntity)
   at System.Data.Entity.Core.Objects.EntityEntry.AddRelationshipDetectedByForeignKey(Dictionary`2 relationships, Dictionary`2 principalRelationships, EntityKey relatedKey, EntityEntry relatedEntry, RelatedEnd relatedEndFrom)
   at System.Data.Entity.Core.Objects.EntityEntry.DetectChangesInForeignKeys()
   at System.Data.Entity.Core.Objects.ObjectStateManager.DetectChangesInForeignKeys(IList`1 entries)
   at System.Data.Entity.Core.Objects.ObjectStateManager.DetectChanges()
   at System.Data.Entity.Core.Objects.ObjectContext.DetectChanges()
   at System.Data.Entity.Internal.InternalContext.DetectChanges(Boolean force)
   at System.Data.Entity.Internal.Linq.InternalSet`1.ActOnSet(Action action, EntityState newState, Object entity, String methodName)
   at System.Data.Entity.Internal.Linq.InternalSet`1.Add(Object entity)
   at System.Data.Entity.DbSet`1.Add(TEntity entity)

The actual lines of code that causes it:

var convertedFoos = ReadFoosFromForeignSource();    //returns a list of anonymous objects with two fields: Foo Original, Foo Converted
UpdatedFooData(convertedFoos.Where(x => x.Original != null));
var newFoos = convertedFoos.Where(x => x.Original == null).Select(x => x.Converted).ToList();

foreach (Foo newFoo in newFoos)
{
    db.Foos.Add(newFoo);    //error happens here
}

I am reading Foo XML from a foreign source and converting it to local Foo format and then either: updating the existing object or adding the new object to the database.

When the error is thrown (shown by a comment above), db, db.Foos, and newFoo are not null. Inspected newFoo more closely reveals tons of null properties inside of newFoo, but they are all allowed to be null.

Based on the stacktrace I am making the assumption that this is related to collection properties. So I inspected the collection properties more closely and found that none of the collections are null and none of the FK properties of the collection objects are null.

Upvotes: 2

Views: 4596

Answers (1)

JaxFirehart
JaxFirehart

Reputation: 61

Because of the error Entity Framework was throwing and my inability to step into Entity Framework code, I struggled to find the precise error. After some effort I pulled the Entity Framework source code into my project, got it compiling, and debugged the error like I would any other one. I discovered the problem.

I had:

public class Foo
{
    public int Id {get; set;}
    public List<FooBar> FooBars {get;set;}
}

public class Bar
{
    public int Id {get; set;}
    public List<FooBar> FooBars {get; set;}
}

public class FooBar
{
    [Key, Column(Order=1)]
    public int FooId {get; set;}
    public Foo Foo {get; set;}

    [Key, Column(Order=2)]
    public int BarId {get; set;}
    public Bar Bar {get; set;}

    public RelationshipEnum Relationship {get; set;}
}

All of this was to create a relationship between Foo and Bar that also specified the type of relationship.

I was reading data from an external source and creating or updating these relationships. The problem was in my update code:

I was sloppy in determining which FooBar relationship I was updating. If I happened to try to update the wrong one, I was attempting to change one of the composite keys which wasn't allowed.

I fixed this by adding an Id property to my FooBar class and sorting by that to ensure that it was always retrieved from the database in the order it was added. I also had to clear out all old data (I imagine fixing it might have worked, but because I could re-pull it from my foreign source, it was easier to just remove the data and re-pull).

Some extra data I gleaned about how Entity Framework works:

When using the DbSet<T>.Add(T entry) method, it checks for changes in ALL LOADED ENTRIES, not just the one you added, which is why I was getting errors on every single add with no determinable pattern. It was finding the same error in the same Entry for every Entry I tried to add.

TL;DR

My code was trying to change the composite key on an object in a strange way that was causing Entity Framework to choke when validating relationships on all loaded Entries (which it does on every call to add a new Entry).

Upvotes: 3

Related Questions