我们有两个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;
}
....
}
儿童:
@Entity
@EntityListeners({ ParentListener.class })
public class children {
private Boolean status = false;
@ManyToOne
private Parent parent;
}
在我的控制器/服务类中( 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
和交易/会话以及EntityListeners
的误解是什么?
PS。 AutowireHelper是here
的引用答案 0 :(得分:2)
我相信你误解了三种不同的反应性回调@PostPersist
,@PostUpdate
和@PostLoad
之间的微妙差异。
仅在实体首次加载到持久性上下文或正在刷新实体的状态时才会触发@PostLoad
回调。前者在执行查找或查询时发生,后者在您在实体实例上调用refresh时发生。
类似地,@PostPersist
回调在第一次持久化实体后触发,而@PostUpdate
回调在现有实体更新后触发。
在处理Spring Data时,当您在save
上调用Repository
方法时,该方法可能会导致持久性提供程序调用{{1}}或persist
操作取决于实体对象是临时的/新的还是现有的,可能是分离的实体实例。
也就是说,您可能需要一系列监听器回调来管理您所追求的生命周期。这是因为当您修改merge
实体并保存它时,这不一定会在关联上传播侦听器回调。
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 );
}
}
}
现在只需将// 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>
。