JPA @Transient在调用方法之前清除@PreUpdate字段

2022-09-03 15:41:07

我有一个用户实体类,我正在尝试为其执行密码哈希。我认为最简单的方法是创建一个用@Transient注释的密码字段和一个散列密码字段,该字段是在对象使用带有@PrePersist和@PreUpdate注释的方法持久化之前设置的。

所以我有这样的东西:

@Transient
private String password;

private String hashedPassword;

@PrePersist
@PreUpdate
private void hashPassword() {
    if(password != null) {
        hashedPassword = PasswordHasher.hashPassword(password);
    }
}

当实体持久化时,这完全可以正常工作。密码字段仍然在调用 hashPassword 时设置,并且计算和存储 hashedPassword 的值。

但是,对于更新,情况并非如此 - 即使在合并实体之前设置了密码的新值,在调用hashPassword时,该字段也为空。这是为什么呢?瞬态字段的值难道不应该至少在实体持久化之前一直存在吗?

(我正在使用EclipseLink 2.0.0 btw,如果它有任何区别的话)


答案 1

我通过在“瞬态”字段上将可更新的und insertable设置为false来解决这个问题,所以在你的情况下,这将是:

@Column(name = "password", insertable = false, updatable = false)
private String password;

因此,需要一个@column表(这有点丑陋),但它永远不会被填满(出于安全原因,这在我的情况下很重要)。

我测试了Hibernate 4.3.4.Final,它对我有用。该字段值在我的 EntityLister @PrePersist和@PreUpdate方法中可用,但未存储在数据库中。

希望这可以帮助任何有类似问题的人。


答案 2

如上面的答案中所述,这是规范中的设计。EclipseLink 包含一个不属于 JPA 规范的事件(postMerge),应该在周期的正确位置为您调用。在 EclipseLink 2.1 中,描述符 Event Adaptor 类可以使用常规@EventListeners注释进行注册,在 2.1 之前,您需要添加使用 EclipseLink 原生 API 的 even。

@EntityListeners({
    a.b.MyEventListener.class,
})

package a.b;

import org.eclipse.persistence.descriptors.DescriptorEvent;
import org.eclipse.persistence.descriptors.DescriptorEventAdapter;

public class MyEventListener extends DescriptorEventAdapter {

    public void postMerge(DescriptorEvent event) {
        //event.getSession();
        //event.getObject();
        //event.getOriginalObject();
    }
}

推荐