我有一个新对象。我想在保存之前知道 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);
}
使用 @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 的值)每第二条评论更新
@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;
}
}
}
事实上,如果你在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;
@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
第一步使用名为
@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,您可以在需要的地方重复使用,这将在单个事务中提供。希望这对其他人有帮助。