JPA 2.0(Hibernate 4.2.4.Final/Spring 3.2.8.Release)/ Mysql 5.6
对于托管实体E w /自动生成的主键,例如
...
@Id
@GeneratedValue
private int id;
@Column
private String foo;
@Version
@Column(name="mod_date")
private Timetamp modDate;
...
foo需要等于:{id}:由于遗留原因。例如。如果id是204,foo将是“:204:” 为了实现这一点,在交易中这是有效的
em.persist(e);
em.detach(e);
e = em.find(e.getId());
e.setFoo(":" + e.getId() + ":");
...
是否有更好的方法来计算派生列,其值取决于生成的Id? 没有上述黑客攻击,即在持久化后直接更新列会导致org.hibernate.StaleObjectException。我在单元测试中看到这种情况发生(实际上我可以逐步执行单元测试代码并且可以重现异常,该异常排除了通常与staleObjectException关联的多线程问题
答案 0 :(得分:1)
您可以使用JPA PostPersist事件侦听器来处理此问题。
@Id
@GeneratedValue
private int id;
@Column
private String foo;
@PostPersist
public void onSave(){
foo = ":" + id + ":";
}
从JPA 2规范:
为一个调用PostPersist和PostRemove回调方法 实体被持久化或删除后的实体。这些 还将对所有这些实体调用回调 操作是级联的。 PostPersist和PostRemove方法将会 在数据库插入和删除操作之后调用 分别。这些数据库操作可能直接发生在 已经调用了持久化,合并或删除操作,或者可以调用它们 在刷新操作发生后直接发生(可能是在 交易结束)。 生成的主键值是 可以在PostPersist方法中使用。
答案 1 :(得分:0)
最佳解决方案是使用@Formula:
在加载时简单计算Column值@Formula(value="':'||id||':'")
private String foo;
答案 2 :(得分:0)
您可以为此要求创建拦截器,请参阅下面的示例:
假设您有一个名为Student
的实体,其属性为id
(充当标识符)和foo
。
@Entity
@Table(name = "test_student")
public class Student {
@Id
@GeneratedValue
private int id;
private String foo;
// Setters & Getters
}
现在你可以创建一个拦截hibernate的Empty Interceptor的拦截器,并覆盖onSave
方法,将foo
属性的值设置为:{id}
,如下所示:
import java.io.Serializable;
import org.hibernate.CallbackException;
import org.hibernate.EmptyInterceptor;
import org.hibernate.type.Type;
public class MyInterceptor extends EmptyInterceptor {
public boolean onSave(Object entity, Serializable id, Object[] state,
String[] propertyNames, Type[] types) throws CallbackException {
System.out.println("Entered onSave : class - " + entity.getClass());
if (entity instanceof Student) {
Student s = (Student) entity;
System.out.println("class:" + entity.getClass() + " , id: "+s.getId());
s.setFoo(":"+id);
}
return false;
}
}
现在你需要告诉hibernate使用这个拦截器:
Configuration configuration = new Configuration().setInterceptor( new LogInterceptor() );
configuration.configure();