I'm using eclipselink together with a Coherence distributed cache and a relational database (Toplink Grid - Grid cache configuration). Right now, I'm trying to perform a cache warm-up as efficiently as possible, reducing the number of future connections to the database.
I have a very simple data model: a parent entity (Person) with a one-directional One-To-Many relationship to the childs' entity (MagicCard)
@Entity
@Customizer(GridCacheCustomizer.class)
public class Person implements Serializable {
@Id
private int Id;
@Version
protected int version;
private String surname;
private String name;
@OneToMany(cascade = {CascadeType.ALL}, fetch = FetchType.LAZY , orphanRemoval=true )
@CascadeOnDelete
@JoinColumn(name="person_id_ref")
private List<MagicCard> cardList;
}
@Entity
@Customizer(GridCacheCustomizer.class)
public class MagicCard implements Serializable {
@Id
private int Id;
private String descr;
@Version
protected int version;
}
In order to perform the cache warm-up, I'm doing a query using batch fetch. This way, I avoid the execution of N+1 database selects.
Query q = em.createQuery("select p from Person p");
q.setHint(QueryHints.BATCH, "p.cardList");
q.setHint(QueryHints.BATCH_TYPE, "IN");
q.setHint(QueryHints.LOAD_GROUP_ATTRIBUTE, "cardList");
List<Person> people = (List<Person>) q.getResultList();
which translates in runtime into:
[EL Fine]: sql: Connection(1099217286)--SELECT ID, NAME, SURNAME, VERSION FROM PERSON
[EL Fine]: sql: Connection(1099217286)--SELECT ID, DESCR, VERSION, person_id_ref FROM MAGICCARD WHERE (person_id_ref IN (?,?,?,?))
bind => [1, 2, 3, 4]
This search seems to be filling the Coherence caches for both entities correctly. The following log is from an example with 4 people (with 4,3,1 and 0 cards, respectively):
[EL Fine]: cache: Coherence(Person)::Get: [1, 2, 3, 4] result size: 4
[EL Fine]: cache: Coherence(Person)::ConditionalPut: 1 value: entities.Person hashcode: 558082331
[EL Fine]: cache: Coherence(MagicCard)::Get: [3, 1, 2, 4, 5, 6, 7, 8] result size: 8
[EL Fine]: cache: Coherence(MagicCard)::ConditionalPut: 3 value: entities.MagicCard hashcode: 321885278
[EL Fine]: cache: Coherence(MagicCard)::ConditionalPut: 1 value: entities.MagicCard hashcode: 1206609130
[EL Fine]: cache: Coherence(MagicCard)::ConditionalPut: 2 value: entities.MagicCard hashcode: 1405610448
[EL Fine]: cache: Coherence(MagicCard)::ConditionalPut: 4 value: entities.MagicCard hashcode: 948640159
[EL Fine]: cache: Coherence(MagicCard)::ConditionalPut: 5 value: entities.MagicCard hashcode: 2122449463
[EL Fine]: cache: Coherence(MagicCard)::ConditionalPut: 6 value: entities.MagicCard hashcode: 714661629
[EL Fine]: cache: Coherence(MagicCard)::ConditionalPut: 7 value: entities.MagicCard hashcode: 905115332
[EL Fine]: cache: Coherence(MagicCard)::ConditionalPut: 8 value: entities.MagicCard hashcode: 127827822
[EL Fine]: cache: Coherence(Person)::ConditionalPut: 2 value: entities.Person hashcode: 1268451305
[EL Fine]: cache: Coherence(Person)::ConditionalPut: 3 value: entities.Person hashcode: 1535800224
[EL Fine]: cache: Coherence(Person)::ConditionalPut: 4 value: entities.Person hashcode: 164901111
*****************
cache : class com.tangosol.coherence.component.util.SafeNamedCache -- Person
.------- cache Person size 4
| KEY : 1 - VALUE TYPE : oracle.eclipselink.coherence.integrated.cache.wrappers.entities.Person_Wrapper
| KEY : 3 - VALUE TYPE : oracle.eclipselink.coherence.integrated.cache.wrappers.entities.Person_Wrapper
| KEY : 4 - VALUE TYPE : oracle.eclipselink.coherence.integrated.cache.wrappers.entities.Person_Wrapper
| KEY : 2 - VALUE TYPE : oracle.eclipselink.coherence.integrated.cache.wrappers.entities.Person_Wrapper
'--------------------
cache : class com.tangosol.coherence.component.util.SafeNamedCache -- MagicCard
.------- cache MagicCard size 8
| KEY : 1 - VALUE TYPE : Entities.MagicCard
| KEY : 7 - VALUE TYPE : Entities.MagicCard
| KEY : 3 - VALUE TYPE : Entities.MagicCard
| KEY : 5 - VALUE TYPE : Entities.MagicCard
| KEY : 4 - VALUE TYPE : Entities.MagicCard
| KEY : 6 - VALUE TYPE : Entities.MagicCard
| KEY : 2 - VALUE TYPE : Entities.MagicCard
| KEY : 8 - VALUE TYPE : Entities.MagicCard
'--------------------
*****************
Next, I try to find (using an EntityManager) a specific person, or a specific card
System.err.println("*** FINDING PERSON WITH ID=1 ***");
Person p = em1.find(Person.class, id);
System.out.println("[PERSON] " + p.toString());
and a cache search is successfully performed, as expected:
*** FINDING PERSON WITH ID=1 ***
[EL Fine]: cache: Coherence(Person)::Get: 1 result: entities.Person hashcode: 2132249404
[PERSON] Person [Id=1, name=x, surname=y]
however, when I try to find the cards of a person, eclipselink needs to perform an additional database select (I thought I'd avoid these with batch fetching(?)):
System.err.println("*** FINDING CARDS FROM PERSON WITH ID=1 ***");
Person p = em1.find(Person.class, id);
List<MagicCard> cards = p.getMagicCardList();
System.out.println(cards.size() + " cards found:\n");
---
[EL Fine]: cache: Coherence(Person)::Get: 1 result: entities.Person hashcode: 138084761
[EL Fine]: sql: Connection(278533322)--SELECT ID, DESCR, VERSION FROM MAGICCARD WHERE (person_id_ref = ?)
bind => [1]
[EL Fine]: cache: Coherence(MagicCard)::Get: [3, 1, 2, 4] result size: 4
4 cards found
I was expecting it to get the list of cards from the coherence cache, and not from the database, since I had previously filled the former with everyone's cards. The only way I could get it to work as I desire was to change the @OneToMany FetchType to EAGER, but I'd like to avoid this change, since it has a negative impact in another part of my system.
Weren't the batch and load hints supposed to initialize the childs in the parent object? Or am I doing something wrong? Is there any other/better way of achieving this?
Thanks in advance