如何通过JPA/Hibernate/Spring Boot独立更新嵌套实体的更新字段
JPA/Hibernate实体独立更新审计字段问题
我有一对一对一关联的嵌套实体EntityA和EntityB,需求是仅当实体自身字段发生变更时,独立更新该实体的username和lastUpdateDatetime,关联实体的对应字段不更新:
- 若
EntityB自身字段变更,仅更新EntityB的username和lastUpdateDatetime - 若
EntityA自身字段变更,仅更新EntityA的username和lastUpdateDatetime
实体代码
EntityA
@Entity(name = "EntityA") public class EntityA { @Column(name = "EntityAColumn1") private String entityAColumn1; @Column(name = "EntityAColumn2") private String entityAColumn2; @OneToOne(cascade = CascadeType.ALL) @JoinColumn(name = "EntityA_EntityB") private EntityB entityB; @Column(name = "username", length = 100) private String username; @Column(name = "last_update_datetime") private ZonedDateTime lastUpdateDatetime; }
EntityB
@Entity(name = "EntityB") public class EntityB { @Column(name = "EntityBColumn1") private String entityBColumn1; @Column(name = "EntityBColumn2") private String entityBColumn2; @OneToOne(cascade = CascadeType.ALL, mappedBy = "EntityB", fetch = FetchType.LAZY) private EntityA entityA; @Column(name = "username", length = 100) private String username; @Column(name = "last_update_datetime") private ZonedDateTime lastUpdateDatetime; }
控制器代码
@RestController public class EntityAController { private final EntityARepository entityARepository; @PutMapping("/update") public void updateEntityA( @RequestBody ObjectA objectA, @RequestHeader("username") String username ) { EntityA entityA = EntityMapper.mapToEntity(objectA); entityARepository.save(entityA); } }
注:
EntityMapper.mapToEntity(objectA)仅用于将Web请求映射为实体
仓库代码
@Repository("EntityARepository") public interface ShippingOrderRepository extends CrudRepository<EntityA, Long> { }
数据示例
更新前数据库数据(JSON格式便于阅读)
{ "entityAColumn1": "val1", "entityAColumn2": "val2", "entityB": { "entityBColumn1": "val3", "entityBColumn2": "val4", "username": "username1", "lastUpdateDatetime": "2023-09-20T07:09:30Z" }, "username": "username1", "lastUpdateDatetime": "2023-09-20T07:09:30Z" }
更新请求内容
{ "entityAColumn1": "val1", "entityAColumn2": "val2", "entityB": { "entityBColumn1": "val3", "entityBColumn2": "val5", // 值已变更 "username": "username1", "lastUpdateDatetime": "2023-09-20T07:09:30Z" }, "username": "username1", "lastUpdateDatetime": "2023-09-20T07:09:30Z" }
- 仅
EntityB的entityBColumn2字段发生变更 - 请求头中的
username为"username2"
期望更新结果
{ "entityAColumn1": "val1", "entityAColumn2": "val2", "entityB": { "entityBColumn1": "val3", "entityBColumn2": "val5", // 已更新 "username": "username2", // 已更新 "lastUpdateDatetime": "2023-10-13T07:09:30Z" // 已更新 }, "username": "username1", "lastUpdateDatetime": "2023-09-20T07:09:30Z" }
仅
EntityB的username和lastUpdateDatetime被更新,因其是唯一发生变更的实体
已尝试的无效方案
- 使用
@PreUpdate注解方法:即使仅一个实体变更,两个实体的审计字段都会被更新
@PreUpdate public void preUpdate() { this.username = UsernameUtil.getUserName(); this.lastUpdateDatetime = ZonedDateTime.now(); }
- 使用
@UpdateTimestamp注解更新lastUpdateDatetime:同样会导致两个实体的对应字段都被更新
@UpdateTimestamp @Column(name = "last_update_datetime") private ZonedDateTime lastUpdateDatetime;
注:已实现从请求头获取并存储
username的机制,此处省略相关代码
核心问题
是否存在JPA/Hibernate原生机制,能够实现仅当实体自身字段变更时独立更新其username和lastUpdateDatetime,无需编写大量字段对比方法(实体字段较多时该方式不切实际)?
内容的提问来源于stack exchange,提问作者Vanblerk Havenga
相关产品推荐
相关产品推荐

