@PreUpdate does not work on OneToOne relationship

Viewed 70

We have these two entities

@Entity
@Table
public class A {
  
   // id and other fields
   
   @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "a")
   @JoinColumn(name = "id")
   private B b;

   @PrePersist
   public void doSomePrePersistenceStuff() {
   // performing some pre persistence code
   }

   @PreUpdate
   public void doSomePreUpdateStuff() {
   // performing some pre update code
   }

   // getters & setters
}

and the other class B

@Entity
@Table
public class B {
 
    // id and other fields
    
    @JsonIgnore
    @MapsId
    @JoinColumn(name = "id")
    @OneToOne
    private A a;

    // getters & setters
}

Each time I am persisting A, it gets to the doSomePrePersistenceStuff() method, but if I am modifying B from A, suppose I am modifying some other columns from B, it won't get to doSomePreUpdateStuff(). e.g.

   A a = new A();
   a.setSomeField("someField");
   a.someOtherField(32);

   A persistedA = aRepository.save(A);//right before here it gets to prePersistenceStuff()

   // but if I am trying to provide a B object...
   B b = new B();
   b.setA(A);
   b.setSomeField("field")
   b.someOtherField(555);
   
   persistedA.setB(b);

   persistedA = aRepository.save(persistedA); // here it does not get to preUpdateStuff() 

Can somebody tell why it won't go to the pre update method? It only goes in the pre update method if I change other columns that are non relational. e.g. changing 32 to 444 from A would go to the pre update method. I just want to trigger the preUpdate stuff from A whenever something from B gets modified as well. Do I need to create a separate repository for B in order for that to happen; creating PrePersist / PreUpdate methods in B?

Thank you.

1 Answers

The reason why this is happening is that the owning entity of the relationship is the class B.

You have done so with the attribute mappedBy here

public class A {
       @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "a") <-----
       @JoinColumn(name = "id")
       private B b;
       ...

And also here you ask the extra join column to be embedded into class B

public class B {
    @MapsId
    @JoinColumn(name = "id")
    @OneToOne
    private A a;
    ...

So the only update happening when you affect the relationship between those 2 entities, happens on the side of class B. Therefore the listener @PreUpdate on class A is not triggered.

You can either switch positions of the owning entity, or create another @PreUpdate listener on class B which will fire as you expect it to when the relationship between A and B is modified.

I just want to trigger the preUpdate stuff from A whenever something from B gets modified as well.

Following what I have said above, the listener will be triggered on class A only when there are some relationship changes from class A having to do with class B. For every simple change happening in class B in some basic field you can't trigger the @PreUpdate on class A since the only update method invoked in JPA layer will have to do only with entity class B.

Related