在jpa中保存对象之前如何知道id

问题描述 投票:0回答:4

我有一个新对象。我想在保存之前知道 id。是否可以?或者还有另一种方法吗?我使用jpa作为orm,使用oracle作为数据库。

@Id
@Basic(optional = false)
@Column(name = "ID", nullable = false)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "woTypeSeq")
private Long id;

我的实体中有一个代码字段。如果用户没有为

code
字段输入值,我想将代码设置为实体的 id。如果我持久化实体,当然我可以获取 id 并将代码值设置为 id,但这是额外的查询数据库。

我想做这样的事情

if(entity.getCode()==null) {
   entity.setCode(entity.getId);
   jpaDao.saveOrUpdate(entity);
}
java oracle jpa jpa-2.0
4个回答
14
投票

使用 @GenerateValue 类型 id,您无法提前知道该值(在实际写入之前)。但是,一旦您持久化 Bean,id 字段将填充到该 Bean 实例中,您无需对其进行额外的查询即可获取它。换句话说:

MyEntiry myEnt = new MyEntity(); //the id field is null now
entityManager.persist(myEnt);//the id field is populated in myEnt now
Long id = myEnt.getId();

此外,根据您的

EntityManager
的配置方式,您可能还需要先(手动)提交事务,然后才能获取该 id。

根据评论更新

如果您想在保存和/或更新实体之前拦截实体并对其执行某些操作,则可以使用 JPA LifeCycle Listeners(如果您使用的是 JPA 版本 2):使用侦听器和回调处理 JPA 生命周期事件。

基本上,您可以在 bean 中创建一个

validate()

 方法,用 
@PrePersist
@PreUpdate
 对其进行注释,并在其中进行验证(如果代码为空,则将其设置为 id 的值)

每第二条评论更新

是的,老实说,我刚才想到了这一点:如果 id 是自动生成的,它可能会在 pre-persist 事件之后填充,这样当你的 pre-persist 代码执行时,你仍然不知道 id 是什么是(您可能还注意到,在示例中链接到的 id 不是自动生成的,而是手动设置的)。 在这种情况下,您可以做的是向您的实体添加一个名为

@Transient

 的布尔字段(用 
isCodeEmpty
 注释,这样它就不会被持久化)(如果没有专门初始化,默认情况下为 false)。然后在 
@PrePersist
 带注释的方法中检查 code 字段的值是否为空,如果是,则将布尔值设置为 true。然后重构 
setId(...)
 方法,以便(除了设置 id 字段之外)它将检查此布尔值,如果为 true,则将 code 字段的值设置为 id 字段的值:

public class YourEntity { @Transient private boolean isCodeEmpty; public void setId(Whatever id) { this.id = id; if(isCodeEmpty) { this.code = id; //if necessary: //this.isCodeEmpty = false; } } @PrePersist public void validate() { if(code == null || code.isEmpty()) { isCodeEmpty = true; } } }
    

13
投票
经过长时间研究,终于找到了解决方案。

事实上,如果你在jpa中使用

序列生成器,在将实体保存到数据库之前,你肯定无法获取实体的id,因为下一个id将由数据库序列分配。

有一种获取 id 的方法,如果您使用

自定义生成器,您可以在保存之前获取 id。这是简单的实现:

public class CustomGenerator extends IdentityGenerator implements Configurable { private IdentifierGenerator defaultGenerator; public Serializable generate(SessionImplementor session, Object object) throws HibernateException { Long idValue = (Long)defaultGenerator.generate(session, object); //idValue will be assigned your entity id return idValue; } @Override public void configure(Type type, Properties params, Dialect d) throws MappingException { DefaultIdentifierGeneratorFactory dd = new DefaultIdentifierGeneratorFactory(); dd.setDialect(d); defaultGenerator = dd.createIdentifierGenerator("sequence", type, params); } }

使用 CustomGenerator 作为 id 字段:

@Id @Basic(optional = false) @Column(name = "ID", nullable = false) @GenericGenerator(name = "seq_id", strategy = "com.yoncabt.abys.core.listener.CustomGenerator", parameters = { @Parameter(name = "sequence", value = "II_FIRM_DOC_PRM_SEQ") }) @GeneratedValue(generator = "seq_id") private Long id;
    

4
投票
这是适合我的解决方案:

@Id @GeneratedValue( strategy = GenerationType.SEQUENCE, generator = "my_seq" ) @SequenceGenerator( name = "my_seq", sequenceName = "my_seq" ) @Access( AccessType.PROPERTY ) private Long id; @Column( name = "CODE", nullable = false, updatable = false ) private Long code; public void setId(Long id) { this.id = id; if (code == null) { code = id; } }
重要的部分是放置 

@javax.persistence.Access( AccessType.PROPERTY )

 注解,这使得 Hibernate 使用 getter 和 setter 来访问 id 字段。如果没有它,当 @Id 注解直接放置在字段上而不是字段 getter 上时,Hibernate 将使用基于字段的访问策略(不使用 getter 和 setter)。关联:
https://docs.jboss.org/hibernate/orm/5.1/userguide/html_single/Hibernate_User_Guide.html#access


0
投票
只需按照以下步骤操作即可在完成交易之前获得 ID。

第一步使用名为

@EntityListeners

 的注释在实体级别添加实体侦听器。

@Id @Basic(optional = false) @Column(name = "ID", nullable = false) @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "woTypeSeq") @EntityListeners(SomeLinstener.class) private Long id;
第二步

public class SomeLinstener{ @PostPersist public void userPostPersist(YourEntity obj) { try { obj.getId(); }catch(Exception e) { } }
这将为您提供一个由生成器生成的 ID,您可以在需要的地方重复使用,这将在单个事务中提供。

希望这对其他人有帮助。

© www.soinside.com 2019 - 2024. All rights reserved.