0

So, the question at hand is about initializing the lazy collections of an "unknown" entity, as long as these are known at least by name. This is part of a more wide effort of mine to build a generic DataTable -> RecordDetails miniframework in JSF + Primefaces.
So, the associations are usually lazy, and the only moment i need them loaded is when someone accesses one record of the many in the datatable in order to view/edit it. The issues here is that the controllers are generic, and for this I also use just one service class backing the whole LazyLoading for the datatable and loading/saving the record from the details section. What I have with come so far is the following piece of code:

public <T> T loadWithDetails(T record, String... associationsToInitialize) {
    final PersistenceUnitUtil pu = em.getEntityManagerFactory().getPersistenceUnitUtil();
    record = (T) em.find(record.getClass(), pu.getIdentifier(record));
    for (String association : associationsToInitialize) {
        try {
            if (!pu.isLoaded(record, association)) {
                loadAssociation(record, association);
            }
        } catch (..... non significant) {
            e.printStackTrace(); // Nothing else to do
        }
    }
    return record;
}

private <T> void loadAssociation(T record, String associationName) throws IntrospectionException, InvocationTargetException, IllegalAccessException, NoSuchFieldException {
    BeanInfo info = Introspector.getBeanInfo(record.getClass(), Object.class);
    PropertyDescriptor[] props = info.getPropertyDescriptors();
    for (PropertyDescriptor pd : props) {
        if (pd.getName().equals(associationName)) {
            Method getter = pd.getReadMethod();
            ((Collection) getter.invoke(record)).size();
        }
    }
    throw new NoSuchFieldException(associationName);
}

And the question is, did anyone start any similar endeavor, or does anyone know of a more pleasant way to initialize collections in a JPA way (not Hibernate / Eclipselink specific) without involving reflection?
Another alternative I could think of is forcing all entities to implement some interface with

Object getId();
void loadAssociations();

but I don't like the idea of forcing my pojos to implement some interface just for this.

1 Answers1

1

With the reflection solution you would suffer the N+1 effect detailed here: Solve Hibernate Lazy-Init issue with hibernate.enable_lazy_load_no_trans

You could use the OpenSessionInView instead, you will be affected by the N+1 but you will not need to use reflection. If you use this pattern your transaction will remain opened until the end of the transaction and all the LAZY relationships will be loaded without a problem.

For this pattern you will need to do a WebFilter that will open and close the transaction.

Community
  • 1
  • 1
uaiHebert
  • 1,882
  • 11
  • 21
  • Yeah, well N+1 effect is not an issue here. As i described in the question, basically associations will be loaded only when I need the "details" view, so it's not gonna be N queries, but 1 more per association. Also, JPA standard doesn't allow you to retrieve more than a One-To-Many association anyway, so this is required. Now, about the OpenSessionInView, the question was not about that. It was about loading the associations in a generic way at the time of loading. Something that should force those associations to be loaded. – Eduard Korenschi Aug 20 '14 at 09:34
  • You said that "JPA standard doesn't allow you to retrieve more than a One-To-Many association anyway" where you saw that? I have executed several queries like: "select p from Person p join fetch p.cars join fetch p.pets". – uaiHebert Aug 20 '14 at 21:53