This has bugged me for years but I cannot find anything about it in jpa references nor this site. When an entity has a computed member (Inverse via mappedby, @Formula, …), there doesn’t seem to be any way to get a transactionally consistent update of that computed member. The pattern seems to be that the setter of the one side needs to know about the consumers and update them in situ. I must be missing something. Hopefully the below is illustrative enough.
I wouldn’t mind if the requirement was that I had to call em.getReference or .find again on the obj w/ the computed members just in case the ones from the original fetch are out of sync, but that just returns the exact same instance w/ no updates of the fields.
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.PersistenceContext;
import org.springframework.transaction.annotation.Transactional;
@Entity
public class InverseProblemDto {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
@OneToMany(mappedBy="problem")
public Set<OwnerDto> owners;
public int otherField = 0;
}
@Entity
public class OwnerDto {
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private int id;
@ManyToOne
public InverseProblemDto problem;
public int yetAnotherField = 0;
}
@Transactional
public void wontWork(int dbId) {
@PersistenceContext
EntityManager em;
InverseProblemDto probDto = em.find(InverseProblemDto.class, dbId);
probDto.otherField++;
for (OwnerDto other : probDto.owners) {
// do something
}
OwnerDto newOwner = new OwnerDto();
newOwner.problem = probDto;
em.persist(newOwner);
// do more
// How to ensure this finds newOwner w/o breaking transactional integrity by forcing a flush and refresh???
for (OwnerDto other : probDto.owners) {
if (other.id == newOwner.id) System.out.println("Yeah! found it");
}
}
Flush and refresh do not commit the transaction but only issue the pending sql to the database.
You could always change the value yourself like this :
}