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

Java 在jpa中保存对象之前,如何知道id,java,oracle,jpa,jpa-2.0,Java,Oracle,Jpa,Jpa 2.0,我有一个新对象。我想在保存它之前知道它的id。可能吗?还是有别的办法?我使用jpa作为orm,使用oracle作为数据库 @Id @Basic(optional = false) @Column(name = "ID", nullable = false) @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "woTypeSeq") private Long id; 我的实体中有一个代码字段。如果用户没有为code字段

我有一个新对象。我想在保存它之前知道它的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,但这是额外的查询数据库

@Id
@Basic(optional = false)
@Column(name = "ID", nullable = false)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "woTypeSeq")
private Long id;
我想做那样的事

if(entity.getCode()==null) {
   entity.setCode(entity.getId);
   jpaDao.saveOrUpdate(entity);
}

使用@GeneratedValue类型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生命周期侦听器(如果您使用的是JPA版本2):

基本上,您可以在bean中创建一个
validate()
方法,用
@PrePersist
@PreUpdate
对其进行注释,并在其中进行验证(如果代码为空,则将其设置为id值)

每2条评论更新一次 是的,我刚才真的想到了这一点:如果id是自动生成的,那么它可能会在预持久化事件之后填充,这样当执行预持久化代码时,您仍然不知道id是什么(您可能还注意到,在示例中,链接到id的不是自动生成的,而是手动设置的)。 在这种情况下,您可以向名为
iscodempty
的实体添加一个布尔字段(用
@Transient
注释,因此它不会被持久化)(如果没有特别初始化,默认情况下为false)。然后在带注释的
@PrePersist
方法中检查code字段的值是否为空,如果为空,则将布尔值设置为true。然后重构
setId(…)
方法,这样(除了设置id字段外)它将检查此布尔值,如果为true,则将代码字段的值设置为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;
 }

}


}
@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;

经过长时间的研究,我终于找到了解决办法

事实上,如果您在jpa中使用序列生成器,那么在将实体的id保存到数据库之前肯定无法获取该实体的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字段:

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;
 }

}


}
@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

第一步使用名为
@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,您可以在需要时重用它,这将在单个事务中提供


希望这对其他人有所帮助。

您可以避免使用@GeneratedValue,自己使用生成器获取值并“手动”将其设置为entity。我不想手动将其设置为entity。如果我从oracle获取id的下一个值并将其设置为新实体的id,它合理吗?谢谢你的回答。我更新了我的问题。你能检查一下吗?我试过实体侦听器。但在prepersist中id值为null。我不知道为什么它为null。我这样实现=你有建议或想法吗?非常感谢您您的想法非常好,但在预科生setId()方法无效之后。我照您说的做了。我正在调试它,但是setId方法没有执行,代码字段没有设置。Prepersist正在工作。请告诉我可配置接口的包好吗?我看到很多包都包含这个,但是没有一个包有方法配置(类型类型、属性参数、方言d)抛出MappingException{}这个ID可以在prepersist中使用吗??