1

From How and when should I load the model from database for h:dataTable I love the idea of essentially caching data from a database in a PostConstruct method and subsequently accessing it in memory as many times as JSF wants to without a trip to the database, but I'm struggling with how to load and store it in memory. The classic object-to-relational impedance mismatch.

My model classes (beans, pure data objects) depend on other classes, i.e. objects contain other objects which are shared (e.g. a course has a student that is also in other courses). I am forced to do one of the following, all of which seem awkward:

  • denormalize the in-memory data (beans) completely (different copies of the same student object appear in different course objects). I don't like copies of data which can get out of sync.
  • use ID attributes (the course class has a studentID member). This necessitates looking up the student in the list of students using the ID whenever any student attribute is needed. Ecch.
  • load all the data from bottom up in the contains hierarchy (load all the students, then load the courses, and for each course find the already-loaded related student object and put a reference to that object in the course object). This is a lot of searching but only has to be done once. If there are any circular references it won't work.

In addition, in order to make sure the model (the in memory data) is always in sync with the database, I would think that one would save and then load all the data every time the user changes any data, rather than incrementally change it in memory and then in the database and hope that I didn't forget to do this every time.

In a non-JSF application, it would not be heavy to hit the database with each user interaction unless the data were enormous, which would necessitate designing around performance rather than object-oriented anyway.

I am curious how others have approached this problem.

Kukeltje
  • 12,223
  • 4
  • 24
  • 47
snakedog
  • 357
  • 1
  • 2
  • 13
  • 1
    Why would it not be heavy for a non-jsf application and heavy for a jsf one? Most if not all of the issues you mention arise for JSF **and** non-JSF in my opinion. You could also use a 2nd level cache, refreshing it (entity listeners?) and more... The only thing I ran into were the merging of detached objects and if you do things the wrong way, you get entitymanager closed errors. – Kukeltje Jan 06 '18 at 08:30
  • All of this seems not to be related with the view layer at all. I think you're struggling with your ORM library rather than with JSF itself. If you're using an ORM like Hibernate, keep in mind it already provides a first level cache which works at session level and avoids having to load the same entity twice (if there are many students with the same course, it will load the course only one, referencing that object from all the students implied, which tears down your first assumption). For the second assumtion, I would just use a Hashmap, which allows you to have a O(1) lookup. – Aritz Jan 08 '18 at 12:14
  • 1
    All in all, I think you should have a look to Guava's and Spring's (if you're using it at all) caching mechanisms before implementing something yourself, if you go with a homebrewn solution. – Aritz Jan 08 '18 at 12:15
  • Thanks for your responses. In a non-JSF app I would have no problem calling the database every time the user asks to CRUD data and it would be once per request. The JSF display layer is very chatty (https://stackoverflow.com/questions/2090033/why-jsf-calls-getters-multiple-times is an example of many SO posts on this) and I agree with @BalusC that this necessitates some form caching to avoid unnecessary DB calls. I think this is straightforward with simple non-normalized data. I agree with you that my question is about how to cache which is JSF-independent. – snakedog Jan 08 '18 at 18:01
  • I am using Spring but not caching, and I think I want to have more control over the caching than I would have by delegating it to Spring or Hibernate but I don't know. My question is indeed about ORM and the best way to do this - in-memory normalization using Java object references, same using explicit IDs, or no normalization at all. The necessity for this is occasioned by the use of JSF (which I won't give up without a fight!), hence the JSF reference. I am sure I am not the first to face this problem but I have probably not framed it clearly. – snakedog Jan 08 '18 at 18:11

2 Answers2

2

I use JSF with a complex database (and Hibernate ORM) a lot. My approach is very similar to what you linked and I never had any problems with it.

There are a few things to keep in mind to prevent troubles though:

  • never do caching over more requests, it's a headache to solve all the lazy loaded relations
  • when caching collections, remember to force refreshing them when you change anything (adding/removing a member), I do it like this:

    private List<Person> people = null;
    private Person person = null;
    
    private void initPeople() {
        this.people = this.peopleDao.getPeople();
    }
    
    public List<Person> getPeople() {
        // this will be called first in the restore view phase
        // then a few times later depending on the references in the
        // JSF page
        if (this.people == null) {
            initPeople();
        }
        return this.people;
    }
    
    public void savePerson() {
        // this will be called in the update model phase
        // so we reset the people collection to force its
        // re-initialization in later phases (like render response)
        peopleDao.savePerson(this.person);
        this.people = null;
    }
    

And I have a RequestListener, that manages the request-scoped hibernate session for the DAOs:

public class RequestListener implements ServletRequestListener {
    @Override
    public void requestInitialized(ServletRequestEvent sre) {
        // Create a Hibernate session and store it to a request scoped bean
    }

    @Override
    public void requestDestroyed(ServletRequestEvent sre) {
        // Close the Hibernate session created for this request
    }
}

Of course you could do it in a simple request-scoped bean in a @PostConstruct and @PreDestroy, but this way I can mix my JSF with plain servlets, which I do a lot.

  • Thanks for this. Hibernate caching, in fact any caching (I use ehcache) would definitely solve this problem, and I'm guessing in the same way I'm doing it - by constructing the objects in memory normalized - parent objects share references to child objects rather than containing copies. – snakedog Jan 08 '18 at 17:52
1

On thinking this through, I think this is as others have suggested a caching question, not a JSF question, although I suspect others who use JSF have had to consider the issue of caching data in an object model in memory due to JSF's chatty nature in the view.

In the end I chose to write my own small ORM for my app: load the entities that have no dependencies in them first, then the entities that depend on them, and on up the contains hierarchy. This necessitates a not-very-scalable search through the lower-level entities to find the ones I want by ID - e.g. when constructing a course object from DB query results which contain studentIDs, iterate through all the student objects already loaded to find the ones I want. This seems a little awkward to me but it's the best I could come up with and the data size in this particular app is pretty manageable. This is probably simply due to my ignorance of how object-relational mapping is done.

I still face the question of how to efficiently refresh this cached object model when data changes. Thanks so much for your responses!

snakedog
  • 357
  • 1
  • 2
  • 13