首页 > 解决方案 > 使用非自动生成的 ID 保存在 JPA/Hibernate 中的替代方法

问题描述

我正在尝试将一个值插入到 ID 中为 String 类型的数据库中。

@Entity
@Table(name = "xpto_version_map")
public class XptoVersionMap implements Serializable {
    @Id
    @Column(name =  "uniq_name", unique = true, nullable = false)
    private String uniq_name;
...

尝试保存新的 XptoVersionMap() 时,例如:

XptoVersionMap xptoVersionMap = new XptoVersionMap();
xptoVersionMap.setUniqName("XPTO-1");
xptoVersionMap.setValue("value2");

xptoVersionMapRepository.save(xptoVersionMap);

会抛出:

org.springframework.orm.jpa.JpaObjectRetrievalFailureException: Unable to find xxx.api.database.entity.XptoVersionMap with id XPTO-1; nested exception is javax.persistence.EntityNotFoundException: Unable to find xxx.api.database.entity.XptoVersionMap with id XPTO-1.

我尝试了不同的解决方案,但除非我可以进行本机查询来插入值,否则我无法告诉 Hibernate 我只想检查 @Id (uniq_name) 是否存在,如果不插入新的值而不是抛出异常。

标签: javahibernatespring-bootjpaspring-data-jpa

解决方案


这就是 Hibernate 默认的工作方式。当您执行保存方法并且未设置 ID 时,它会分配一个自动生成的 ID。如果有一个 ID,它会尝试更新它(在你的情况下会发生什么)。

保存实体。如果不存在,将分配一个标识符。如果是这样,它本质上是在进行更新。返回生成的实体 ID。

例如,您可以通过使用 persist 和 @PrePersist 来解决问题

@PrePersist
void generateId() {
    if (uniq_name == null) {
        uniq_name = GENERATE_SOME_UNIQUE_ID_SO_IT_DOESN'T_BREAK();
    }
}

然后使用 xptoVersionMapRepository.persist(xptoVersionMap);

或者你可以用类似的东西编写你自己的生成器:

@GenericGenerator(name = "my_generator", strategy = "package.CustomGenerator")
@GeneratedValue(generator = "my_generator")

然后创建一个实现 IdentifierGenerator 的类 CustomGenerator 并创建所需的方法。


推荐阅读