【问题标题】:only fetch @ManyToOne releationship but dont persist Parent Entity仅获取 @ManyToOne 关系但不保留父实体
【发布时间】:2015-11-11 13:43:44
【问题描述】:

我有以下实体:

@Entity
public class Parent {

    @Id
    @Column(name = "ID", nullable = false)
    private Long id;

}


@Entity
public class Child {

    @Id
    @Column(name = "ID", nullable = false)
    private Long id;

    private Parent parent;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "PARENT_ID", referencedColumnName = "ID", updatable = false, insertable = false)
    public Parent getParent() {
        return parent;
    }

}

现在,当我保存子项时,我想将父项的 ID 保存到“PARENT_ID”列中。
但是我不想在保存子项时保存或更新父项。
因此,我已将 updatable = false, insertable = false 添加到 @JoinColumn。
问题是,这样我得到“org.hibernate.TransientPropertyValueException:对象引用了一个未保存的瞬态实例 - 在刷新之前保存瞬态实例”。
所以 Hibernate 告诉我在 Child 之前先保存 Parent。好吧,Parent 已经保存了,但是 Hibernate 不知道,因为它是一个新事务,我不想要 再次保存父级(这就是updatable = false, insertable = false 的重点)。我也不想再次获取父项(没有额外的选择,我只需要 ID(我已经拥有)而不是整个对象)

我已经尝试使用 @Transient 注释 getParent 以防止 Parent 的持久化,这很好用,但是当获取 Child 时,Parent 不是。
(我用我手动设置的另一个属性保存了 ID)

有什么方法可以实现我想要的吗?
(取子时取父,保存子时保存ParentID,但不保存或更新父)

【问题讨论】:

    标签: java hibernate jpa spring-data


    【解决方案1】:

    问题似乎在于您正在创建一个新父级,尽管您只想将一个新子级附加到现有父级。不要那样做。由于父级已经存在,从EntityManager中获取:

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "PARENT_ID")
    public Parent getParent() {
        return parent;
    }
    

    并且,要使用现有的父 ID 保存新的子项:

    Parent existingParent = entityManager.getReference(Parent.class, parentId);
    Child child = new Child();
    child.setParent(existingParent);
    entityManager.persist(child);
    

    【讨论】:

    • 两个愚蠢的问题: 1. 从 Spring @Component 获取 entityManger 的最佳方法? (@Autowire?) 2. 这是否有效,即使 Parent 保存在另一个事务中并且 Child 是在新事务中创建的?
    • 1. @PersistenceContext private EntityManager entityManager; (但我假设您已经拥有它,因为您已经尝试拯救孩子)。 2. 是的,当然。为什么不呢?
    • 遗憾的是我还没有那个。保存是通过存储库(spring.data.repository)完成的。但我确实在 servlet.xml 中定义了 entityManagerFactory,所以我想我会试一试。 :-)
    • 您绝对应该继续使用存储库:Parent existingParent = parentRepository.getOne(parentId)getOne() 方法将使用底层的 EntityManager.getReference() 方法。 docs.spring.io/spring-data/jpa/docs/current/api/org/…
    • 我接受了你的回答,尽管我不得不使用不同的“解决方案”。尽管看起来我不知道自己在做什么(也许那是真的),但我正在使用一个可怕的代码库,实际情况比我的简单示例要复杂得多。因此,我无法让您的解决方案发挥作用,但我确实认为它是正确的,它只是不适合我的代码库 xD
    【解决方案2】:

    正如对 JB Nizet Answer 的评论,我不得不使用不同的解决方案,但我认为如果可以的话,您应该使用他的解决方案。

    我的解决方案如下所示:
    - 从 getParent() 中删除 @ManyToOne 和 @JoinColumn 并使用 @Transient
    对其进行注释 - 添加另一个属性(长 parentId)
    - 使用 @Column("PARENT_ID") 注释 parentId - 当从数据库加载子项时,我获取 parentId 并加载父项并通过其 Settermmethod 将其添加到子项

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-11-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-03
      • 2021-06-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多