0

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!

godsim
  • 181
  • 1
  • 9
  • Basically, that's what happens within in a single transaction. – Mihe Oct 10 '22 at 17:52
  • That's what I thought, and I annotated the method containing the JPA readAll() calls to both B's and C's, yet the same parents had a different object identities. Would Spring tell me with an error or warning that the transactional context is in fact not applied to the method, or just fail silently? – godsim Oct 11 '22 at 07:22
  • You annotated readAll() or the class containing this method with `@Transactional`? – Mihe Oct 11 '22 at 09:23
  • @Mihe I added an additional code snippet regrding the "@Transactional" part. – godsim Oct 12 '22 at 07:07
  • 1
    You coud try to debug this, e. g. [this answer](https://stackoverflow.com/a/69894165/19657183) might be helpful. – Mihe Oct 12 '22 at 09:54
  • @Mihe Although my problem had another cause, this was very helpful in understanding when Spring opens and closes certain transactions in my code. Thank you very much! – godsim Oct 12 '22 at 13:20

1 Answers1

1

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.

godsim
  • 181
  • 1
  • 9