Hibernate Spring数据JPA@EntityListeners w/@Transient@PostLoad,属性未更新

Hibernate Spring数据JPA@EntityListeners w/@Transient@PostLoad,属性未更新,hibernate,jpa,spring-data,spring-data-jpa,entitylisteners,Hibernate,Jpa,Spring Data,Spring Data Jpa,Entitylisteners,我们有两个Spring数据JPA实体(父级,子级),即字段设置为特定值的子级计数,在@PostLoad期间影响@Transient属性集中父级记录的值 家长: @Entity public class Parent { @Transient private boolean status = false; @OneToMany @Where("STATUS = true") private Set<Children> childrens; @Po

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

家长:

@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;
   }
....
} 
在我的控制器/服务类(未注释为
@Transactional
)中,我会出现并更新
子记录的状态值:

@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
以及事务/会话和
实体侦听器的误解是什么


PS.AutowireHelper是来自

的参考,我相信您误解了三种不同的反应式回调之间的细微差别
@PostPersist
@PostUpdate
,以及
@PostLoad

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

类似地,
@PostPersist
回调在第一次持久化临时实体后触发,而
@PostUpdate
回调在更新现有实体后触发

在处理Spring数据时,当您在
存储库
上调用
保存
方法时,该方法可能导致持久性提供程序调用
持久化
合并
操作,具体取决于实体对象是暂时的/新的还是现有的、可能分离的实体i安斯坦斯

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

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 );
     }
   }
}
根据用例的不同,如果您试图为一些非持久性任务维护这种瞬态状态,我可能建议在这里使用decorator模式,而不是实体生命周期,因为首先将不同的关注点分开是很重要的

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

// 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();
   }
}

现在只需将
列表
传递到上层,而不是
列表

如果我误解了这一点,很抱歉,因此基本上这只是更新父类中的一个字段以触发父类中的entitylistener?不完全是这样。OP想要一种方法,当子对象的状态发生变化时通知父对象,从而影响到父对象父级上的me状态。前者用作从子级的实体生命周期到父级的回调。后者用于说明可以在实质上包装实体的装饰器对象内单独管理瞬态。后者的好处是通过这些回调避免不必要的cpu周期从child->parent确认,并在需要时将该过程转换为委托,特别是当您仅在UI/biz逻辑中需要此过程时。我不确定我的场景是否相同。我的问题是,当我只更新子表的字段时,我父类的entitylistener没有接收到此更改,或者它检测到我的父类中没有任何更改,所以它没有响应我没打电话。这之所以重要是因为我要参加我父母的“最后修改日期”字段以查看记录是否已更新,但如果仅修改子表,则此lastModifiedDate不会更改。现在,每次更新完成时,我只是从控制器中切换父类中的布尔字段。因此,当修改子类时,让子类的实体侦听器调用父类中执行其操作的方法实体侦听器逻辑。通过这种方式,当父级或子级被修改时,您可以保证两个实体侦听器场景都会调用父级的业务逻辑。然后您应该能够删除布尔值。我明白了,这听起来是合乎逻辑的。但如果我的父级有许多子表,这不意味着我必须创建吗(例10)每个孩子都有不同的实体侦听器,只是为了给家长打电话?如果是这样的话,我会将其视为一种情况,这取决于不同的情况。我只是想弄清楚解决方案,仅此而已。但感谢您回复一篇旧帖子!:)
// 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();
   }
}