17

我有一个新对象。我想在保存之前知道 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);
}
4

4 回答 4

13

经过长时间的研究,我终于找到了解决方案。

事实上,如果你在jpa中使用sequence generator,在将它保存到数据库之前,你肯定无法获得实体的id,因为下一个id将由数据库sequence分配。

如果您使用自定义生成器,则有一种获取 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;
于 2013-02-07T16:44:11.627 回答
13

使用 @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 LifeCycle Listeners(如果您使用的是 JPA 版本 2):使用侦听器和回调处理 JPA 生命周期事件

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

每第二条评论更新

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

}


}
于 2012-10-05T09:02:09.447 回答
1

这是对我有用的解决方案:

    @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/chapters/domain/access.htmlhiber

于 2021-07-05T17:38:44.987 回答
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,您可以在需要的地方重用它,这将在单个事务中提供。

希望这对其他人有帮助。

于 2019-08-28T09:03:02.740 回答