Load entire graph object at runtime in Hibernate

Please read before saying anything line by line "indicate the type of selection in the query." This is not what I want.

I am looking for a way to load a complete graph object (object + all its children and all their children, etc.).

I want to not list all the properties that need to be loaded. I do not know them until runtime.

N + 1 queries are not a problem. But at the end of this magical operation, I don’t want one proxy or lazy collection left on my chart.

It should be possible to write some code that will reflect and examine all properties recursively. But collections make it uncomfortable and complicated.

Some people have recommended Dozer for this kind of thing, but that seems a bit overkill, so I would like to keep this as a last resort.

+4
source share
2 answers

A simple solution would be to specify lazy="false" for all collections (1: N and N: M) and associations (1: 1).

This will load the entire chart into memory for each transaction. Therefore, for this to work correctly, you must have no more than one transaction or it will really hurt performance, really bad.

As long as this does what you want, the cost may be too high. Note that you can use “profile selections” to select different strategies at runtime, but Hibernate always gives you a copy that you work with when you request objects, so it must copy the graph every time.

For me, it looks like Hibernate - it's just the wrong tool for the task. Matching objects with Hibernate is convenient, but at the cost of merging Hibernate in your model and business code. If the restrictions imposed by Hibernate do not match your account, you should look elsewhere.

Perhaps you can live with Record types rather than compiling Java beans completely. If so, then you can look at jOOQ or frames that implement the "active recording" template .

If you need beans and you are not limited to a specific type of database, try an OO database like db4o .

Finally, why are you using SQL at all? If you always need the entire graph of objects, why not just serialize it to a file and load it at startup? Or use a resident database .

0
source

I once needed something similar, and I had to use Reflection to solve it. In my case, I used hql to retrieve the records. Also, this is the approach I created for active boot records that are defined as lazy loading, so you can adapt the first method so you don’t look for the FetchType.LAZY property and always retrieve it independently.

One of the methods I built will “prepare” a lazy choice. There are basically two approaches: using "left join fetch" in hql for @ManyToOne and hibernate.initialize () for @OneToMany and @ManyToMany.

So, this first method returns a string with the required “left john fetch” es for hql, and also builds a list of nToMany fields that should be called by Hibernate.initialize () after the query is completed.

 private String buildLazyFetch(Class<? extends GenericEntity> entityClass, List<String> nToManyFields) { String lazyFetches = new String(); lazyFetches += " fetch all properties "; // iterate through all fields looking for lazy loaded relationships for (Field f : entityClass.getDeclaredFields()) { ManyToOne manyToOne = f.getAnnotation(ManyToOne.class); if (manyToOne != null) { if (manyToOne.fetch().equals(FetchType.LAZY)) { lazyFetches += " left join fetch t." + f.getName() + " "; } } OneToMany oneToMany = f.getAnnotation(OneToMany.class); if (oneToMany != null) { if (oneToMany.fetch().equals(FetchType.LAZY)) { nToManyFields.add(f.getName()); } } ManyToMany manyToMany = f.getAnnotation(ManyToMany.class); if (manyToMany != null) { if (manyToMany.fetch().equals(FetchType.LAZY)) { nToManyFields.add(f.getName()); } } } return lazyFetches; } 

and after executing hql call:

 private void lazyFetchNToMany (List<String> nToManyFields, GenericEntity entity) { for (String field : nToManyFields) { try { Hibernate.initialize(BeanUtils.getProperty(entity, field)); } catch (HibernateException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } } } 

I understand that this is not quite what you expected, but it can help you in case you do not find the solution you need.

0
source

All Articles