I have the following entities:
class A {
@Id
String aId;
@OneToMany(fetch = FetchType.LAZY)
List<B> bsOfA
@OneToMany(fetch = FetchType.LAZY)
List<C> csOfA
public A(String id) {
this.aId = id;
}
}
class B {
@Id
String aId;
@Id
String bId;
@ManyToOne(fetch = FetchType.LAZY)
A aOfB;
@ManyToOne(fetch = FetchType.LAZY)
C cOfB // this is some member of csOfA
public B(String id, B sourceB) {
this.aId = id;
this.bId = sourceB.bId;
}
}
class C {
@Id
String aId;
@Id
String cId;
@OneToMany(fetch = FetchType.LAZY)
A aOfC;
@ManyToOne(fetch = FetchType.LAZY)
List<B> linkedBsToC;
public C(String id, C sourceC) {
this.aId = id;
this.cId = sourceC.cId;
}
}
Now I want to create a copy of A so I proceed as follows
A sourceA = aRepo.getbyId(sourceAId);
A copyA = new A(newAId);
List<B> bsOfA = new ArrayList<>(sourceA.getBsOfA.size());
sourceA.getBsOfA().forEach(b -> bsOfA.add(new B(newAId, b));
copyA.setBsOfA(bsOfA)
List<C> csOfA = new ArrayList<>(sourceA.getCsOfA.size());
// problematic part
sourceA.getCsOfA().forEach(c -> csOfA.add(new C(newAId, c));
copyA.setCsOfA(csOfA)
Now the issue is: during this copy operation, I am observing that when constructor of C is called, the input c is a hibernate_interceptor object that has null attributes (like in this other post: Data inside hibernate interceptor object but null under entity variables - Can't save to repository).
To remedy this situation, I have 3 choices:
- Swap the position of initializing copyA's bsOfA and csOfA:
List<C> csOfA = new ArrayList<>(sourceA.getCsOfA.size());
sourceA.getCsOfA().forEach(c -> csOfA.add(new C(newAId, c));
copyA.setCsOfA(csOfA)
List<B> bsOfA = new ArrayList<>(sourceA.getBsOfA.size());
sourceA.getBsOfA().forEach(b -> bsOfA.add(new B(newAId, b));
copyA.setBsOfA(bsOfA)
- Set FetchType.EAGER for cOfB
- Modify the constructors
public C(String id, C sourceC) {
this.aId = id;
this.cId = sourceC.getCId(); // How is this different from sourceC.id ?!
}
Can someone please enlighten me on this issue? I will most definitely opt for #3 because it seems the easiest to adjust but I still can't figure out what is wrong with the original code. Many thanks in advance :)
hibernate_interceptoryou getting is proxy class.getByIdwhich will return a lazy proxy. The proxy works on intercepting method calls, you are doing direct field access. So if you callgetCId()the proxy will do a query to obtain the information, if you do direct field access it won't. Replacing thegetByIdwith afindByIdwill remedy this as well as it will now fetch the full A object, and when accessing the collection will fetch the entities (as opposed to the proxy returned fromgetById).