由于一个或多个外键属性不可为空,因此无法更改关系

时间:2013-04-13 22:08:57

标签: c# sql-server .net-4.0 entity-framework-4

(注意:即使它具有相同的例外情况,也是this question的副本。)

我有一个穷人的交易,其策略是:

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

      

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

    我一般都明白这意味着什么,但我以为我是按照规则玩的,无论我怎么努力遵守规则,我都不确定为什么我会收到这条消息。

    我们使用自我跟踪实体,我的代码实际上是这样的:

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

    这种逻辑有什么问题?为什么我不能简单地删除这两个记录?我致电MyContext.ApplyChanges后尝试拨打MarkAsDeleted。我已经尝试了各种各样的事情,无论如何,无论我多么努力地告诉Context我希望两者都被删除,它仍然会抛出这个异常。

1 个答案:

答案 0 :(得分:4)

@Slauma在上述评论中提供了这个答案,但要求我发布答案。

问题在于实体框架的自我跟踪实体模板中存在“错误”(Microsoft不再建议您使用此模板)。专门针对此主题的博客文章可以是found here

具体来说,问题是上下文的ObjectStateManager与(附加的)实体'ChangeTracker.State不同步,并且您最终拥有entity.ChangeTracker.State == ObjectState.Deleted的对象,但{{1}认为状态设置为context.ObjectStateManager。这两者显然非常不同。因此,此修复有效地进行并查找附加到上下文的任何对象EntityState.Unchanged,但深入挖掘并检查每个对象的EntityState.Unchanged ChangeTracker.State以解决问题。

通过使用以下代码替换ObjectState.Deleted块,可以在Context的T4模板中轻松且非常全面地解决此问题(对我们来说效果很好):

#region Handle Initial Entity State