C# 无法更改关系,因为一个或多个外键属性不可为null

C# 无法更改关系,因为一个或多个外键属性不可为null,c#,sql-server,.net-4.0,entity-framework-4,C#,Sql Server,.net 4.0,Entity Framework 4,(注意:这不是的副本,即使它有相同的例外情况。) 我有一笔穷人交易,策略如下: 插入父记录和子记录 执行长时间运行的操作 如果长时间运行的操作失败,请删除以前插入的父记录和子记录 当我尝试第3步时,我收到以下消息: 操作失败:无法更改关系,因为一个或多个外键属性不可为null。对关系进行更改时,相关外键属性设置为空值。如果外键不支持空值,则必须定义新的关系,必须为外键属性分配另一个非空值,或者必须删除不相关的对象 我大致理解这意味着什么,但我认为我是按规则玩的,无论我多么努力地按规则玩,我不确定

(注意:这不是的副本,即使它有相同的例外情况。)

我有一笔穷人交易,策略如下:

  • 插入父记录和子记录
  • 执行长时间运行的操作
  • 如果长时间运行的操作失败,请删除以前插入的父记录和子记录
  • 当我尝试第3步时,我收到以下消息:

    操作失败:无法更改关系,因为一个或多个外键属性不可为null。对关系进行更改时,相关外键属性设置为空值。如果外键不支持空值,则必须定义新的关系,必须为外键属性分配另一个非空值,或者必须删除不相关的对象

    我大致理解这意味着什么,但我认为我是按规则玩的,无论我多么努力地按规则玩,我不确定为什么我会得到这个信息

    我们使用自跟踪实体,我的代码是:

    var parent = new Parent(1,2,3);
    var child = new Child(4,5,6);
    parent.Children.Add(child);
    
    MyContext.Parents.ApplyChanges(parent);
    MyContext.SaveChanges(SaveOptions.AcceptAllChangesAfterSave);
    
    // At this point, inserts were successful and entities are in an Unchanged state.
    // Also at this point, I see that parent.Children.Count == 1
    
    var shouldDeleteEntities = false;
    try
    {
      // This is not database-related. This process does some
      // encryption/decryption and uploads some files up to
      // Azure blob storage. It doesn't touch the DB.
      SomeLongRunningProcess();
    }
    catch
    {
      // Oops, something bad happened. Let's delete the entities!
      shouldDeleteEntities = true;
    }
    
    // At this point, both entities are in an Unchanged state, child still
    // appears in parent.Children, nothing is wrong that I can see.
    parent.MarkAsDeleted();
    child.MarkAsDeleted();
    
    // I've tried MyContext.ApplyChanges here for both entities, no change.
    
    // At this point, everything appears to be in the state that
    // they're supposed to be!
    try
    {
      MyContext.SaveChanges(SaveOptions.AcceptAllChangesAfterSave);
    }
    catch
    {
      // This exception was thrown and I can't figure out why!
    }
    
    这种逻辑有什么问题?为什么我不能简单地删除这两条记录?我尝试在调用
    MarkAsDeleted
    后调用
    MyContext.ApplyChanges
    。我尝试了各种各样的方法,不管怎样,不管我多么努力地告诉上下文我想要删除它们,它总是抛出这个例外。

    在上面的评论中提供了这个答案,但要求我发布答案

    问题在于实体框架的自跟踪实体模板中实际上存在一个“bug”(Microsoft不再推荐您使用)。一篇关于这个主题的博客文章可以是

    具体来说,问题在于上下文的
    ObjectStateManager
    与(附加的)不同步实体的
    ChangeTracker.State
    和您最终拥有的对象具有
    entity.ChangeTracker.State==ObjectState.Deleted
    ,但当
    上下文.ObjectStateManager
    认为状态设置为
    EntityState.Unchanged
    时。这两者显然是非常不同的。因此,此修复程序可以有效地查找作为
    EntityState.Unchanged
    附加到上下文的任何对象,但需要深入挖掘,并检查每个对象的
    ChangeTracker.State
    中的
    ObjectState.Deleted
    以修复问题

    通过将
    #区域句柄初始实体状态
    块替换为以下代码,可以在上下文的T4模板中对此问题进行简单且功能非常全面的解决(这对我们来说非常有效):

    #region Handle Initial Entity State
    
    var existingEntities = context
        .ObjectStateManager
        .GetObjectStateEntries(System.Data.EntityState.Unchanged)
        .Select(x => x.Entity as IObjectWithChangeTracker)
        .Where(x => x != null);
    
    var deletes = entityIndex.AllEntities
                        .Where(x => x.ChangeTracker.State == ObjectState.Deleted)
                        .Union(existingEntities
                                .Where(x => x.ChangeTracker.State == ObjectState.Deleted));
    
    var notDeleted = entityIndex.AllEntities
                        .Where(x => x.ChangeTracker.State != ObjectState.Deleted)
                        .Union(existingEntities
                                .Where(x => x.ChangeTracker.State != ObjectState.Deleted));
    
    foreach (IObjectWithChangeTracker changedEntity in deletes)
    {
        HandleDeletedEntity(context, entityIndex, allRelationships, changedEntity);
    }
    
    foreach (IObjectWithChangeTracker changedEntity in notDeleted)
    {
        HandleEntity(context, entityIndex, allRelationships, changedEntity);
    }
    
    #endregion
    

    你不能像这里这样做吗:?我不确定,但我们有反对级联删除的策略。我从未与EntityFramework合作过,我与NHibernate合作过,通常我们会级联。如果无法级联,则应删除其中一个,提交,然后删除另一个。因为您不是级联的,所以框架无法通过删除这两个元素来猜测您正在进行有效的删除。从我与NHibernate的经验来看,这就是问题所在。我明白了。上面的代码是否使用自跟踪实体?如果是的话,我建议在你的问题或标签中,甚至在标题中强调这一点,因为自跟踪实体已经成为一种“异国情调”(并且不推荐)的EF方法。也许这与问题有关:你能写下答案吗?事实上,我不知道这篇文章在说什么:)我只是无意中在谷歌上搜索了一下,看到了“STE”和“删除不起作用”之间的关联。我认为,如果你把自己对STEs和这篇文章的理解与答案结合起来,对其他读者来说会更有价值?