MyEntity是一个具有生成ID的经典JPA实体。我想自动将字段(myStringField)设置为基于id的值。在这个例子中,如果id为43,我想将它设置为“foo43”。
由于DB是由DB自动生成的,因此在em.persist(myEntity)调用之前它为null。但是在持久化之后,它具有由Hibernate分配的id(在DB序列上称为NEXTVAL)。所以,我虽然声明了@PostPersist方法,但如下所示:
package ...;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.PostPersist;
@Entity
public class MyEntity {
@Id @GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String myStringField;
@PostPersist
public void postPersist(){
System.out.println("The id = " + id);
this.myStringField = "foo" + id;
}
public String getMyStringField() {
return myStringField;
}
...
}
以下是一些创建并保留实体的代码:
package ...;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Transactional
@Service
public class MySpringBean {
@PersistenceContext EntityManager em;
public void createMyEntity() {
MyEntity myEntity = new MyEntity();
em.persist(myEntity);
System.out.println(myEntity.getMyStringField());
}
}
它打印以下输出:
The id = 47
foo47
哪个好。但是,在DB中,字段myStringField为null!有人知道为什么吗?
我确实希望在MyEntity.postPersist()方法期间将实体标记为脏,并且在刷新期间更新将在事务结束时发生。但显然不是。
我使用的是Hibernate v4.2.4
有人知道为什么这个DB记录有空值吗?
答案 0 :(得分:1)
就是这样!我做了额外的测试,实际上,在刷新期间调用@PostPersist(可能是因为在刷新期间发送了SQL INSERT)。总而言之,事情按此顺序发生:1。em.persist(),1.1 NEXTVAL发送到DB并且myEntity.id被分配,@Transactional方法的2结束并且执行了flush。 2.1 INSERT发送到DB。 2.2 @PostPersist跟注。 2.2.1 myEntity.myStringField已分配且实体已脏。然后不执行进一步的刷新(和脏检查和更新)=>没有DB保存。非常感谢!!!
答案 1 :(得分:0)
你这样做是持久的,所以它在写入数据库之后就会发生。
根据JPA @PostPersist usage对规范状态的回答
These database operations may occur directly after the persist, merge, or remove operations have been invoked or they may occur directly after a flush operation has occurred
答案 2 :(得分:0)
保存MyEntity后@PostPersist代码正在运行。因此,如果您想确保使用更新的值保存字段myStringField:“foo”+ id,那么在@PostPersist代码之后,您将需要再次保存实体。
因此,如果您将代码更改为:
MyEntity myEntity = new MyEntity();
em.persist(myEntity);
em.persist(myEntity);
理论上,这应该正确保存更新的myStringField。虽然这有点尴尬。不确定您的整个用例,但您可以考虑在数据库本身中编写一个“插入触发器”,为您解决此问题。
答案 3 :(得分:0)
使用
@PrePersist
相反,但是你的方法字段生成对我来说不正确,因为如果你的myStringField即将成为业务id,与jpa id不同,你应该假设它是在bean初始化时创建的。
有关如何处理业务ID的更多示例,我建议您查看有关equals()/ hashcode()困境的此线程,特别是此响应:https://stackoverflow.com/a/5103360/2598693
答案 4 :(得分:0)
要回答您的问题,您不应该在数据层中执行此类操作。该插入和更新应由您的业务逻辑层处理。
但如果您真的需要数据层,请使用@PrePersist。