【问题标题】:NHibernate object references an unsaved transient instance save the transient instance before flushingNHibernate 对象引用未保存的瞬态实例 在刷新之前保存瞬态实例
【发布时间】:2013-11-30 09:43:42
【问题描述】:

我正在尝试保存一个内部包含许多引用元素的复杂对象,并且它在大多数情况下都能完美运行。
但是在某些情况下,我们会遇到以下异常,

object 引用了一个未保存的瞬态实例 - 在刷新之前保存瞬态实例,或将属性的级联操作设置为使其自动保存的内容。类型:Namespace.Core.Client.ClientDetails,实体:Namespace.Core.Client.ClientDetails

问题是,我们试图保存的复杂对象中大约有 12 个 ClientDetails 元素。有没有办法确定是哪个对象实例导致了这个问题? 通过 NHibernate 日志记录或其他方式? 我用于保存的代码示例如下,

_repository.Save<SuperParent>(obj);
_repository.Flush();

请注意,当我将 Nhibernate show_sql 设置为 true 时,我能够看到正确生成的所有查询,但是当调用 flush 时,会引发异常。

请帮助解决问题。

【问题讨论】:

  • 只是一个提示。每个对象是由 NHibernate 区分的,如果它是新的/暂时的要插入或现有的要更新。对于int ID,它是:ID &gt; 0 对象是现有的,ID == 0 对象是新的。尝试在 Flush 之前检查哪个对象没有生成 ID……这将是可疑的。有了这个,你可以找到它所属的 Property 集合并用 cascade 属性标记它...... NHibernate 然后将为你保存所有的东西
  • 查看内部异常(如果存在)。通常 NHibernate 会为未保存的对象(其中 ID 为 0)抛出异常。所以异常/内部异常应该给你足够的细节来弄清楚。
  • 嗨 Radim,是的,我试图收集所有生成的查询。但它分两步发生。 1. 当 _repository.Save(obj) 被调用时,NHibernate 会生成所有需要的 INSERT sql 查询,而不需要 FK 引用。 2. 当 _repository.Flush() 被调用时,NHibernate 生成 UPDATE 查询以更新所有对象之间的所有 FK 引用,并且它没有发现 'ClientDetails' 元素的 UPDATE 少一个并抛出此异常。如果我的,请纠正我理解是错误的,建议。
  • 嗨 MichaC,没有内部异常详细信息,它只提供实体名称,并且没有对象 ID 或其他值,我们可以通过这些值识别导致问题的确切对象实例。谢谢跨度>

标签: c# nhibernate


【解决方案1】:

异常意味着该对象引用了一个未保存的ClientDetails 实例。您必须在保存父级之前手动保存它

session.Save(Parent.SomeDetail);

或在父映射中的引用映射上设置Cascade.SaveOrUpdate

【讨论】:

  • 嗨,最后我们找到了问题,有一个对象的技术参考链接到我试图保存的父对象中的对象在不同的​​对象树中,这意味着这个 cliendetails 参考不是对象树的一部分,但一个特定的实例是指这个。当我更正这个对象时,我能够成功保存它。感谢您的所有释放
  • @Firo 您能否详细说明(如果可能,使用代码 sn-p)如何更改父映射中的流畅引用映射?
  • References(x =&gt; x.DetailProperty).Cascade.All();
【解决方案2】:

如果你仔细阅读:

...在刷新之前的瞬态实例或 设置级联操作 将属性设置为使其自动保存的内容

所以,也许您可​​以将 Cascade 添加到 Reference,如下所示:

References(x => x.ClientDetails).Cascade.All().Column("ClientDetailsId")
                  .Not.Nullable();  //Or nullable, this depends on your schedule

【讨论】:

    【解决方案3】:

    编辑您的映射以级联所有更改。如果您有一个有许多 ClientDetails 的客户端类,您的 xml 映射将是这样的

    在 Client.hbm.xml 文件中你应该有:

    <set name = "ClientDetails" table = "`ClientDetail`" cascade = "all-delete-orphan" inverse="true"> 
             <key column = "ClientId"/> 
             <one-to-many class = "ClientDetail"/> 
    </set>
    

    在 ClientDetail.hbm.xml 文件中你应该有:

    <many-to-one name = "Client" class = "Client" column = "ClientId " />
    

    【讨论】:

      【解决方案4】:

      当您有一个包含作为引用数据的子级的复杂对象时也会发生此错误(想想 ClientType 类)。 如果孩子的映射文件中有一个版本元素映射到数据库中的 int 列,则现有行的版本号永远不应设置为 0。Nhibernate 将其解释为要在级联更新中插入的对象,并将失败,因为它试图插入已经存在的行。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-11-08
        • 2015-09-27
        • 2021-03-03
        • 2017-04-12
        • 2012-02-27
        相关资源
        最近更新 更多