gpt4 book ai didi

hibernate - Spring Data JPA @EntityListeners w/@Transient @PostLoad,属性未更新

转载 作者:行者123 更新时间:2023-12-04 01:59:24 27 4
gpt4 key购买 nike

我们有两个 Spring Data JPA 实体(父、子),子项的字段设置为特定值的计数,影响在 @Transient 属性中设置的父项记录的值@PostLoad

家长:

@Entity
public class Parent {
@Transient
private boolean status = false;

@OneToMany
@Where("STATUS = true")
private Set<Children> childrens;

@PostLoad
public void postload(){
if(childrens.size() > 0) this.status = true;
}
....
}

children :

@Entity
@EntityListeners({ ParentListener.class })
public class children {

private Boolean status = false;

@ManyToOne
private Parent parent;
}

在我的 Controller /服务类(NOT 注释为 @Transactional 中,我来更新 Children 的状态值记录:

@Service 
public class ChildrenService {

...
public void doStuff(Children child) {
child.status = true;
childRepository.save(child);
}
}

现在 ParentListener 启动,我想在父级状态值更改时记录。

class ParentListener {

@PostUpdate // AFTER Children record updated
public void childPostPersist(Children child) {
AutowireHelper.autowire(this);
// here child.parent.status == false (original value)
// but I have set this child record equal to true, and
// have triggered the `save` method, but assuming I am still
// in the session transaction or flush phase, the
// parent related record's status is not updated?
System.out.println(child.parent.status); // prints false
Parent currentParent = parentRepository.getOne(child.parent.getId());
System.out.println(currentParent.status); // prints false
}
}

我对 @Transactional@PoSTLoad 和事务/ session 以及 EntityListeners 有什么误解?

附言。 AutowireHelper 引用自 here

最佳答案

我相信您误解了三种不同响应式(Reactive)回调之间的细微差别 @PostPersist , @PostUpdate , 和 @PostLoad .

@PostLoad仅当实体首次加载到持久性上下文中或刷新实体的状态时才会触发回调。前者发生在您执行查找或查询时,后者发生在您对实体实例调用刷新时。

同样,@PostPersist@PostUpdate 期间首次持久化临时实体后触发回调更新现有实体后触发回调。

在处理 Spring Data 时,当您调用 saveRepository 上的方法,该方法可能导致持久性提供程序调用 persistmerge操作取决于实体对象是 transient /新的还是它是否是现有的、可能分离的实体实例。

也就是说,您可能需要一系列监听器回调来管理您所追求的生命周期。这是因为当你修改你的 Child实体并保存它,这不一定会在关联上传播监听器回调。

public class Children {
/**
* When the change is persisted or updated, make sure to trigger
* the callback on the parent to update its status accordingly
*/
@PostPersist
@PostUpdate
public void updateParentAssociationStatusOnPersistOrUpdate() {
if ( parent != null ) {
parent.updateStatusOnPersistOrUpdateOrLoad();
}
}
}

public class Parent {
/**
* When the parent is loaded, refreshed, or after being persisted
* or updated, this method will insure that the status based on
* child association is properly maintained.
*/
@PostLoad
@PostPersist
@PostUpdate
public void updateStatusOnPersistOrUpdateOrLoad() {
if ( children != null && !children.isEmpty() ) {
setStatus( true );
}
}
}

根据用例,如果您试图为某些非持久性任务维护这种 transient 状态,我可能建议在此处使用装饰器模式而不是实体生命周期,因为保持不同关注点很重要首先分开。

实现此装饰器模式的一种方法可能包括以下内容:

// An interface that defines the parent's contract
public interface Parent {
default boolean getStatus() {
return false;
}
// other methods
}

// Entity implementation of the parent contract
@Entity(name = "Parent")
public class ParentImpl implements Parent {
// implement all non-default methods
// #getStatus will be implemented in the decorator
}

// A view/decorator object that implements the parent contract
public class ParentView implements Parent {
private final Parent parent;

public ParentView(Parent parent) {
this.parent = parent;
}

// all methods delegate to the parent

@Override
public boolean getStatus() {
return !parent.getChildren().isEmpty();
}
}

现在只需传递一个 List<ParentView>到上层而不是List<Parent> .

关于hibernate - Spring Data JPA @EntityListeners w/@Transient @PostLoad,属性未更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48453777/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com