【问题标题】:Saving related entities at once - An error occurred while saving entities that do not expose foreign key properties for their relationships立即保存相关实体 - 保存不为其关系公开外键属性的实体时发生错误
【发布时间】:2016-12-07 03:16:20
【问题描述】:

(我查了相关问题,没有找到答案。)

我正在使用 Code First Entity Framework 6 进行一些测试。 我有一个引用两个“父”实体的“子”实体。

我想创建子实体和父实体,然后一次保存它们(这样我可以减少 db.Save() 调用的数量,并将其保留为一个工作单元)。

public class Child
{
    public int ChildID { get; set; }
    public string Name { get; set; }

    public virtual Parent Father { get; set; }
    public virtual Parent Mother { get; set; }
}

public class Parent
{
    public int ParentID { get; set; }
    public string Name { get; set; }

    [ForeignKey("Child")]
    public int? ChildID { get; set; }
    public virtual Child Child { get; set; }
}

(有点令人困惑的设置——父母实际上是关系中孩子的“孩子”。我知道这是不好的抽象。这只是一个测试。)

控制器:

    public ActionResult AddWithParents()
    {
        Parent father = new Parent { Name = "Test Father" };
        Parent mother = new Parent { Name = "Test Mother" };

        Child newChild = new Child
        {
            Name = "Test Child",
            Father = father,
            Mother = mother
        };


        db.Children.Add(newChild);

        father.Child = newChild;
        mother.Child = newChild;

        db.SaveChanges();            

        return RedirectToAction("Index");
    }

这可行,但不会填充 Parent.ChildID 外键。

如果我执行诸如father.Child = newChild 之类的操作,我会收到以下错误:

保存不为其关系公开外键属性的实体时发生错误。 EntityEntries 属性将返回 null,因为无法将单个实体标识为异常源。通过在实体类型中公开外键属性,可以更轻松地在保存时处理异常。有关详细信息,请参阅 InnerException。 无法确定相关操作的有效排序。由于外键约束、模型要求或存储生成的值,可能存在依赖关系。

有什么方法可以让它工作吗?

【问题讨论】:

  • 你内心的异常是什么?如果它显示SqlException,请检查您的日期时间数据类型是否存在空值或超出范围的值(如果存在)。
  • 模型中没有数据时间。有人重新格式化了我的问题,因此内部异常是主要异常的一部分,但内部异常是:无法确定相关操作的有效排序。由于外键约束、模型要求或存储生成的值,可能存在依赖关系。
  • 好吧,你的内部异常告诉我你有循环依赖问题,EF 试图找到一个具有空或无效主键值的实体。检查外键是否具有可为空的类型或检查相关表之间的关系。那么,你想建立什么样的关系(1:1, 1:n)?

标签: c# entity-framework ef-code-first


【解决方案1】:

我在您的代码中找到了问题来源:Parent 类中的 ChildId 属性声明为可空整数类型,而 Child 类中的 ChildId 属性属于不可空整数类型,它们是不同的类型(Nullable<int>int)。

因此,您应该将Parent 类中的ChildId 属性声明为不可为空的类型,因此循环引用问题应该这样解决:

public class Child
{
    public int ChildID { get; set; }
    public string Name { get; set; }

    public virtual Parent Father { get; set; }
    public virtual Parent Mother { get; set; }
}

public class Parent
{
    public int ParentID { get; set; }
    public string Name { get; set; }

    [ForeignKey("Child")]
    public int ChildID { get; set; } // set this FK as non-nullable int
    public virtual Child Child { get; set; }
}

根据this answer,当外键属性数据类型与源主键不匹配,或者外键属性设置错误时,会出现循环依赖问题。

编辑: 由于Child 类中的ChildId 属性在数据库表中是不可为空的int 主键属性,因此消除循环依赖的最佳方法是设置具有相同数据的外键键入作为主键(即int)。

相关问题:

Clean way to deal with circular references in EF?

Unable to determine a valid ordering for dependent operations

【讨论】:

  • 外键可以为空。使 ChildID 可以为空将编译,但如果您在迁移后查看数据库,ChildID 仍然不允许空值,因为它是主键。因此,父对象的父(子)对象仍将具有空 ID。不过感谢您的努力。我同意最好删除循环引用。
  • 好吧,我错过了Child 类中的ChildId 是主键属性的点。我编辑了解决方案,将Parent 类中的FK ChildId 字段设置为不可为空的int 类型,因此它与Child 表主键定义匹配。
猜你喜欢
  • 2011-12-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-08
  • 2015-06-04
相关资源
最近更新 更多