How do I know the id before saving an object in jpa

北城余情 提交于 2020-08-22 04:29:07

问题


I have a new object. I want to know id before saving it. Is it possible? Or there is another way for this? I am using jpa as orm and oracle as database.

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

I have a code field in my entity. If the user doesn't enter a value for the code field, I want to set code as entity's id. If I persist entity, of course i can get id and set code value as id, but this is extra query database.

I want to do something like that

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

回答1:


After long researching about this, finally I found a solution.

In fact, if you use sequence generator in jpa, certainly you cannot obtain entity's id before saving it in database, because next id will be assigned by database sequence.

There is one way to obtain the id if you use a custom generator, you can get the id before saving. Here is simple implementation:

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

Using CustomGenerator for id field:

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



回答2:


With a @GeneratedValue type id you can't know that value in advance (before actually writing it). However once you persist your Bean, the id field will be populated in that bean instance and you can obtain it without needing to do an extra query for it. In other words:

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();

Also, depending on how your EntityManager is configured, you might need to also first commit the transaction (manually) before you can get that id.

Update as per comment

If you want to intercept and do something to the entity before it is saved and/or updated, you can use JPA LifeCycle Listeners (if you're using JPA version 2): Handling JPA lifecycle event using listeners and callbacks.

Basically you can make a validate() method in your bean, annotate it with @PrePersist and @PreUpdate and do the validation in it (if code is empty set it to id's value)

Update per 2nd comment

Yes, I honestly just thought of that just now: that if the id is auto generated, it might get populated AFTER the pre-persist event, such that when your pre-persist code is executed you still don't know what the id is (you may notice also that in the example you link to the id is NOT autogenerated but set manually). What you can do in this case is add a boolean field to your entity (annotated with @Transient so it won't get persisted) called isCodeEmpty (which is false by default if not specifically initialized). Then in your @PrePersist annotated method you check if the value for code field is empty and if so, set the boolean to true. Then you refactor your setId(...) method such that (aside from setting the id field) it will check this boolean, and if true set the value of the code field to that of the id field:

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

}


}



回答3:


Just follow these steps then you will get the id before you complete the transaction 1st step adds an entity listener at your entity level by using the annotation called "@EntityListeners".

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

2nd step

public class SomeLinstener{

    @PostPersist
    public void userPostPersist(YourEntity obj) {

        try {
            obj.getId();
        }catch(Exception e) {

        }
    } 

this will you an id which has been generated by your generator and you can reuse where ever it is required this will give in a single transaction.

hope this will help for somebody else



来源:https://stackoverflow.com/questions/12742826/how-do-i-know-the-id-before-saving-an-object-in-jpa

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!