始终为 JPA @Id 使用原始对象包装器而不是原始类型?
Posted
技术标签:
【中文标题】始终为 JPA @Id 使用原始对象包装器而不是原始类型?【英文标题】:Always use primitive object wrappers for JPA @Id instead of primitive type? 【发布时间】:2012-07-02 06:42:04 【问题描述】:我发现了将原始类型用作 JPA 的对象 @Id 与 Spring Data JPA 结合使用的问题。 我在父方与 Cascade.ALL 有父/子关系,并且子有 PK,同时也是父的 FK。
class Parent
@Id
private long id;
@OneToOne(mappedBy = "parent", cascade = ALL)
private Child child;
class Child
@Id
@OneToOne
private Parent parent;
所以,当我跑步时:
...
Parent parent = new Parent();
Child child = new Child(parent);
parent.setChild(child);
em.persist(parent)
...
一切正常。但是我使用 Spring Data JPA 来持久化实体,所以我改为运行:
parentRepository.save(parent); // instead of em.persist(parent);
这个失败了,但有以下异常:
Caused by: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: Parent
问题在于 Spring Data JPA save() 方法检查实体是否是新的,如果是新的,则使用 em.persist() 否则 em.merge() 被使用。
这里有趣的部分是 Spring 如何检查实体是否是新的:
getId(entity) == null;
当然,这是错误的,因为我使用 long 作为@Id 的类型,而 long 的默认值为 0。当我将 long 更改为 Long 时,一切也适用于 Spring Data JPA。
因此,建议的做法是始终对原始类型使用对象包装器(例如 Long 而不是 long)而不是原始类型。任何将此描述为推荐做法的第三方资源都会非常好。
【问题讨论】:
Primitive or wrapper for hibernate primary keys的可能重复 【参考方案1】:我会使用对象类型。在 xml 映射中,您可以放置一个“未保存的值”属性,但我认为没有直接翻译为此注释。因此,坚持使用对象类型会更安全。
而且大多数程序员都希望标识符中的“null”值表示未保存。
【讨论】:
【参考方案2】:我会说是的,因为您所看到的情况,建议使用对象类型而不是原语。无法区分实体是新实体还是具有原始标识符的预先存在的实体。我使用 hibernate 已经很多年了,我总是使用对象作为标识符。
【讨论】:
以上是关于始终为 JPA @Id 使用原始对象包装器而不是原始类型?的主要内容,如果未能解决你的问题,请参考以下文章
是否始终将 UUID 用于 JPA 实体的 id 属性并在其上使用等于和哈希码?
我是不是应该始终将 InputStream 包装为 BufferedInputStream?