【问题标题】:hibernate - how to save parent with detached child休眠 - 如何用分离的孩子保存父母
【发布时间】:2015-08-21 00:48:44
【问题描述】:

我正在从 UI 发送一个对象。该对象将使用对现有子对象的引用来创建。

这是这种关系的简单说明。

class ParentEntity {
    @Id
    Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    private ChildEntity child;
}

class ChildEntity {
    @Id
    Long id;
}



ChildEntity child = new ChildEntity();
child.setId(1);
//parentEntity is created based on data sent from UI
parentEntity.setChild(child);

当我保存这个对象时,Hibernate 给了我“org.hibernate.TransientPropertyValueException: object references an unsaved transient instance”。

我不用去救孩子,因为我根本不换孩子。只需要将孩子的 id 保存在父表中即可。

我尝试使用几个 CascadeType,但没有一个起作用。

【问题讨论】:

  • 我也不想从 db 中选择 child 并设置为 parent ,只是为了保存而不会出错。如果必须,我会的。但是....

标签: hibernate jpa orm


【解决方案1】:

只需为孩子使用代理:

parentEntity.setChild(entityManager.getReference(ChildEntity.class, childId));

这里的重点是使用EntityManager.getReference:

获取一个实例,其状态可能被延迟获取。

Hibernate 将创建仅包含 id 的代理,而不访问数据库。

【讨论】:

  • 谢谢。此解决方案有效,但仍从数据库中选择子实体。当它保持父级时,我可以看到休眠选择日志。这是预期的行为吗?
  • 不,它不应该被加载。您是否明确禁用了 ChildEntity (@Proxy(lazy = false)) 的代理?如果没有,您能否显式启用它(用@Proxy 注释实体)然后重试?
  • 或者,是ChildEntityfinal
  • 好的,这是完美的工作解决方案。使用 getReference(),它不会检索子节点来保存父节点。我的问题的原因是我的应用程序在持久化后刷新实体并从父实体中拉出子实体以将更新的数据返回给 UI。这时候,它被找回了。对不起我的困惑。无论如何,我需要一个针对我的情况的解决方法。
【解决方案2】:

您必须决定如何将 ChildEntity 与 ParentEntity 持久化。

  1. 如果你总是想只通过 id 来保留孩子,那么你可以这样做,如果它的孩子无效,FK 会阻止你。

    class ParentEntity {
        @Id
        Long id;
    
        //To directly load/insert/update childId only
        @Column("child_id")
        private Long childId;
    
       // To load the child entity with parent, Note that insertable/updatable MUST be false
       // as we are inserting/updating = true by default on childId column mapping
       @ManyToOne(fetch = FetchType.LAZY)
       @JoinColumn(name = "child_id", insertable = false, updatable = false)
       private ChildEntity child;
    }
    parentEntity.setChildId(childId);
    
  2. 但是,如果您想使用现有模型将子对象映射为对象,那么您必须获取子对象并设置它。 parentEntity.setChild(childRepository.findOne(childId)); 或者 您还可以为 getOrCreateChild 编写一个自定义 DAO 方法,该方法可以创建一个新的孩子或找到现有的孩子并将其返回,以便您可以先保留孩子。

在您使用 new 关键字创建 childEntity 的情况下,hibernate 将始终将其视为分离并尝试持久化。

【讨论】:

  • 我还没有尝试过,但我认为它会起作用。但是,使用此解决方案,当我检索父母时,我不应该得到孩子。
  • 使用 cmets 更新答案,您仍然可以使用父级加载子级,但您必须决定不会通过对象插入/更新子级,因为您决定仅通过 childId 插入/更新..跨度>
  • 如果你想通过对象和 id 来保存孩子,那么你需要一个自定义拦截器,通过注释你的 setter 来加载和设置对象,如果 id 被设置,反之亦然 - 如果对象被设置,则设置 id设置。
猜你喜欢
  • 2023-03-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-26
  • 2012-06-13
相关资源
最近更新 更多