Preserve object identity in parent-child relations of a Hibernate model

71 Views Asked by At

I have the following scenario and could not find any solution for this so far.

Imagine the following Hibernate model consisting of 3 different types with one-to-many relations:

public class A {
  
  @Transient
  private String someRuntimeData;

  @OneToMany
  private Set<B> collA;

  @OneToMany 
  private Set<C> collB;
}


public class B {
  @ManyToOne
  private A parent;
}


public class C {
  @ManyToOne
  private A parent;
}

Imagine that the database contains many B'c and C's that may or may not have a parent relation to A yet. I need to create an in-memory cache that contains all B's and all C's, and unfortunately there is a lot of transient data in different places involved, which requires me to suppress caching multiple instances of the same parent object A.

class SomeClass {
     @Transactional
     protected void init() {
       bList = repoB.readAll();
       cList = repoC.readAll();
     }
  }

The problem is that I don't know how or if it is even possible to tell JPA/Hibernate to retain and reuse an object instance (with its identity) of previously loaded entities in the following way:

Load the full collection of B's with their optional parents of A, then load the full collection of C's, where any transitively loaded instance of A (through B) is reused. Where appropriate, both B and C instances then point to the same in-memory object.

I would be very thankful if anyone could explain on how to realize this with out-of-box features of JPA/Hibernate before I swallow the bitter pill and and remap everything by hand.

Thank you in advance!

1

There are 1 best solutions below

0
godsim On

It was not obvious from the provided code snippets what the problem could have been in this scenario.

For full disclosure, the init() method was called via self-invocation from the classes constructor:

@Component
class SomeClass {
    
    public SomeClass() {
      init();
    }

    @Transactional
    protected void init() {
      bList = repoB.readAll();
      cList = repoC.readAll();
    }
}

Since I did not configure any aspect-weaving for load- or runtime, the compiler created a default Spring Proxy object for SomeClass. Therefore any proxy logic is fully circumvented when self-invocation is in play. In result, the only transactions opened where the default, dedicated ones for each read operations, and the shared parent objects where redundantly loaded.