将新对象添加到DbContext时,Entity Framework中的空引用异常

时间:2018-08-06 17:12:02

标签: c# entity-framework

将新对象添加到DbContext时,我从实体框架内部抛出了nullreferenceexception

堆栈跟踪:

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)

导致它的实际代码行:

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
}

我正在从外部来源读取Foo XML,并将其转换为本地Foo格式,然后执行以下操作:更新现有对象或将新对象添加到数据库中。

引发错误时(如上面的注释所示),db,db.Foos和newFoo不为空。检查过的newFoo可以更紧密地揭示newFoo内部的大量null属性,但都可以将它们设为null。

基于堆栈跟踪,我正在做假设,它与集合属性有关。因此,我更加仔细地检查了集合属性,发现所有集合都不为空,并且集合对象的FK属性都不为空。

1 个答案:

答案 0 :(得分:1)

由于Entity Framework抛出错误,并且由于无法进入Entity Framework代码,因此我难以找到确切的错误。经过一番努力,我将Entity Framework源代码拉到了我的项目中,进行了编译,并像其他任何人一样调试了错误。我发现了问题。

我有:

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;}
}

所有这些都是在Foo和Bar之间创建关系,并指定关系的类型。

我正在从外部来源读取数据并创建或更新这些关系。问题出在我的更新代码中:

我在确定要更新的FooBar关系时草率。如果我碰巧尝试更新错误的密钥,那是在尝试更改不允许的组合键之一。

我通过将Id属性添加到FooBar类并对其进行排序来解决此问题,以确保始终按添加顺序从数据库中检索该属性。我还必须清除所有旧数据(我想修复它可能会起作用,但是由于我可以从国外来源重新拉出它,因此删除数据并重新拉出会更容易。)

我收集了一些有关实体框架如何工作的额外数据:

使用DbSet<T>.Add(T entry)方法时,它会检查所有已加载的条目中的变化,而不仅是您添加的变化,这就是为什么我每次添加都会出错而无法确定的原因图案。对于我尝试添加的每个条目,它都在同一个条目中找到相同的错误。

TL; DR

我的代码试图以一种奇怪的方式更改对象上的组合键,这导致实体框架在验证所有已加载的条目上的关系时(在每次添加新条目的调用中都这样做)导致阻塞。