简体   繁体   English

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

[英]JPA @Transient fields being cleared before @PreUpdate method is called

I have an User Entity class that I'm trying to do password hashing for.我有一个用户实体类,我正在尝试对其进行密码散列。 I thought that the easiest way to do this would be to create a password field annotated with @Transient and a hashed password field that is set just before the object is persisted with a method annotated with @PrePersist and @PreUpdate.我认为最简单的方法是创建一个用@Transient 注释的密码字段和一个散列密码字段,该字段在对象使用@PrePersist 和@PreUpdate 注释的方法持久化之前设置。

So I have something like this:所以我有这样的事情:

@Transient
private String password;

private String hashedPassword;

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

This works perfectly fine when an entity is persisted.当实体被持久化时,这工作得很好。 The password field is still set by the time hashPassword is called, and a value for hashedPassword is calculated and stored.密码字段仍然在调用 hashPassword 时设置,并计算并存储 hashedPassword 的值。

However, the same isn't true for an update - even if a new value for password is set just before merging the entity, the field is null by the time hashPassword is called.但是,更新并非如此——即使在合并实体之前设置了密码的新值,在调用 hashPassword 时该字段为空。 Why is this?为什么是这样? Shouldn't the values of transient fields stick around at least until the entity is persisted?至少在实体持久化之前,瞬态字段的值不应该保留吗?

(I'm using EclipseLink 2.0.0 btw, if it makes any difference) (顺便说一句,我使用的是 EclipseLink 2.0.0,如果有什么不同的话)

I solved this by setting updatable und insertable to false on the "transient" field, so in your case this would be:我通过在“瞬态”字段上将可更新插入设置为 false 来解决此问题,因此在您的情况下,这将是:

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

Therefore a table @column is required (which is kind of ugly) but it will never be filled (which was important in my case for security reasons).因此需要一个表@column(这有点难看)但它永远不会被填充(出于安全原因,这对我来说很重要)。

I tested against Hibernate 4.3.4.Final and it worked for me.我针对 Hibernate 4.3.4.Final 进行了测试,它对我有用。 The field value was useable in my EntityLister @PrePersist and @PreUpdate methods but was not stored in the database.该字段值可用于我的 EntityLister @PrePersist 和 @PreUpdate 方法,但未存储在数据库中。

Hope that helps anybody having similar problems.希望能帮助遇到类似问题的人。

As mentioned in the above answer, this is by design in the spec.正如上面的答案中提到的,这是规范中的设计。 EclipseLink contains an event (postMerge) that is not part of the JPA spec that should be called in the right point in the cycle for you. EclipseLink 包含一个事件 (postMerge),它不属于 JPA 规范的一部分,应该在循环中的正确点为您调用。 In EclipseLink 2.1 The Descriptor Event Adaptor class can be registered using the regular @EventListeners annotation, pre 2.1 you will need to add the even using EclipseLink native API.在 EclipseLink 2.1 中,可以使用常规的 @EventListeners 注释注册描述符事件适配器类,在 2.1 之前,您需要使用 EclipseLink 本机 API 添加偶数。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM