JPA派生列值基于标识列

时间:2014-11-19 06:37:50

标签: hibernate jpa

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关联的多线程问题

3 个答案:

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