【问题标题】:JPA @Transient fields being cleared before @PreUpdate method is called在调用 @PreUpdate 方法之前清除 JPA @Transient 字段
【发布时间】:2011-03-25 13:28:17
【问题描述】:

我有一个用户实体类,我正在尝试对其进行密码散列。我认为最简单的方法是创建一个带有 @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,如果有什么不同的话)

【问题讨论】:

标签: java jpa eclipselink


【解决方案1】:

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

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

因此需要一个表@column(这有点难看)但它永远不会被填充(出于安全原因,这对我来说很重要)。

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

希望对遇到类似问题的人有所帮助。

【讨论】:

  • 这是真的,但是在从表中检索实体时,它会给出 Invalid column name 'password' 异常
【解决方案2】:

如上述答案所述,这是规范中的设计。 EclipseLink 包含一个事件 (postMerge),它不属于 JPA 规范的一部分,应该在循环中的正确位置为您调用。在 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();
    }
}

【讨论】:

  • 出于某种原因,如果我这样做,则调用 postMere 方法,但忽略我的 PrePersist 和 PreUpdate 方法。有什么想法吗?
猜你喜欢
  • 1970-01-01
  • 2022-11-16
  • 1970-01-01
  • 2018-04-09
  • 1970-01-01
  • 2012-03-19
  • 2010-12-25
  • 1970-01-01
  • 2015-06-08
相关资源
最近更新 更多