JPA/Spring/Hibernate/etc 中是不是有类似于 JPA 的 @PrePersist 允许更改相关实体的功能?
Posted
技术标签:
【中文标题】JPA/Spring/Hibernate/etc 中是不是有类似于 JPA 的 @PrePersist 允许更改相关实体的功能?【英文标题】:Is there functionality in JPA/Spring/Hibernate/etc similar to JPA's @PrePersist that would allow changes to related entities?JPA/Spring/Hibernate/etc 中是否有类似于 JPA 的 @PrePersist 允许更改相关实体的功能? 【发布时间】:2021-04-13 16:23:56 【问题描述】:我需要存储某些实体的某些 String
字段的规范化(即没有特殊字符等)变体。
一个例子:
@Entity
public class Car
@Id
private Long id;
private String make;
private String model;
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "CAR_ID")
private Set<NormalizedField> normalizedFields = new HashSet();
private Set<NormalizedField> createNormalizedFields(Car car)
Set<NormalizedField> normalized = normalize(car);
this.normalizedFields.clear();
this.normalizedFields.addAll(normalized);
// I would use this approach, but it doesn't allow
// changes to related entities.
// @PreCreate
// public void onCreate()
// createNormalizedFields();
//
@Entity
public class NormalizedField
@Id
private Long id;
private String fieldName;
private String normalizedValue;
如果在Car
实体被持久化时自动(重新)创建标准化值会很方便。有没有办法自动触发创建方法?
使用@PrePersist, @PreUpdate
... 显然不是一种选择,因为它不允许更改相关实体。
项目中没有使用Spring AOP,所以我宁愿暂时避免引入它。但无论如何,这是一个选择。
应用程序很大,“手动”管理标准化值需要大量工作,因此我将其作为最后一个选项。
【问题讨论】:
使用自定义的UserType
或 AttributeConverter
即可。
@M.Deinum,AttributeConverter
似乎不能用于关系属性。此外,属性本身不包含转换数据,而是需要父实体的状态。自定义UserType
也存在访问父状态的相同问题。
我的错。我应该更仔细地阅读。 prepersist 不应该正常工作吗?我看到的主要问题是您正在清除集合并再次添加所有内容,您应该在其中更新现有的集合。此外,您应该实现正确的 equals amd hashcode 以在 Set 中使用它们。
PrePersist 不起作用,因为它不允许更改其中的 relation 状态。仅限非关系属性。
有趣;想到几个问题:(1)normalize()
的本质是什么?如果它只依赖于当前实体的状态,也许规范化的值不需要被持久化。取而代之的是,在需要时即时进行规范化(并且可能将结果缓存到@Transient
字段)。 (2) 如果它依赖于Car
实体之外的状态,在应用程序逻辑中执行规范化不是更合适吗? (3) NormalizedField
必须是一个实体吗?您能否将其建模为持久值的集合(可能适用于 PrePersist
)?
【参考方案1】:
将在此处发布这个半答案(“半”,因为它提供了一种有限制的解决方法)。
在某些情况下,org.hibernate.Interceptor
可用于在父实体更改时管理子实体。
但有一些限制:javadoc 说Session
不能在Interceptor
中使用。 JPA 存储库方法、JPQL 或 HQL 调用在循环中被相同的Interceptor
拦截。除非您设置 FlushMode.COMMIT
或 FlushMode.MANUAL
(可能还有其他),否则即使是原生查询也会被拦截。
以上意味着您可能必须直接使用数据源。我不记得具体是怎么做的,但是 Spring 提供了直接在当前事务中使用数据源执行查询的方法。就我而言,这已经足够了,因为我必须管理一些不需要以 Entity
表示的技术子实体。
【讨论】:
以上是关于JPA/Spring/Hibernate/etc 中是不是有类似于 JPA 的 @PrePersist 允许更改相关实体的功能?的主要内容,如果未能解决你的问题,请参考以下文章