Announcement Announcement Module
Collapse
No announcement yet.
Hibernate architecture problem with lazy collections Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Hibernate architecture problem with lazy collections

    Hi.

    Let's say I have User object containing Role collections. Mening I have :
    public class User {
    ...
    public Set getRoles() {
    ...

    }

    In my web tier I need to use this User instance, sometimes needing it's roles, and sometimes don't. Does it mean that I would have to create businness method with flag such as :
    public User getUser(Long id, boolean loadRoles)
    and depending upon this flag, to eagerly load roles or not?
    It somehow seems to go against common OO to change businnes interface due to persistnece under the hood. And BTW, Im terrified of OpenSessionInView pattern, thus dont want to apply that pattern.

    Solution?

    -Vjeran

  • #2
    Or you could use OpenSessionInViewFilter

    Comment


    • #3
      Vjeran, I agree, I've become allergic to OSIV in all its forms...

      I've usually implemented my getUser methods as you mentioned above, with a flag stating whether I should load all collections or not.

      The other option seems to be to have a service level object for each use-case. A transactional method in this object is responsible for loading the required domain object, and for touching only those collections required in that particular use-case.

      For view-only use-cases the second approach seems like overkill and I would go with the first one. For use-cases involving view and modify (especially complex modification/validation involving the child objects), I'm now tending towards the second option....

      Hope that helps.

      Best regards,

      Comment


      • #4
        Thanx Assaf.

        One more thing troubles me also... similar to when sometimes I need collection instances in my web tier, and sometimes don't, I stumble upon situations where difefrent web pages have to update persistent object differently - once I want to update just this object's property changes, and sometimes I just want to update it's collections objects (db links in fact), and both of times I have to use Session.update() which effects collection depending upon "cascade" configuration in hbm.xml. Thus, no way to specify in code - now I want collection effected, and now I don't.

        The only solution to this is to load complete object (Session.load) before updating (Session.udapte), thus having collections set in it always. Problem arise when having page with form that is used for updating object. Since there are only form fields for this object's properties, and not some "hidden" fileds about it's collection info, I cannot simply create new instance of this object, and call session.update() since that would erase all collection links (since collection reference is null).

        Comment


        • #5
          Did you test this? I haven't yet come across a situation where spring binding actually causes Hibernate to delete the entire collection.
          Can you post the code where this is happening?

          Comment


          • #6
            well, code would be messy, but here is explained... If you have web page with form for updating some User object, you can place all property values in a form (ID is usually hidden field), thus when you submit, controller fetches all property values, populate newly created (new User()) empty instance with these values (let's say username, password for User instance), and updates it with Session.update(). But problem is that roles collection is null, since no value was available for populating it, and Hibernate thinks that it should delete all links with Session.update() since this collection has cascade="all" set in hbm.xml.

            Comment


            • #7
              Oh, I think I get it.
              Why do you create a new (empty) object after the submit? That's where your problem is. You should be loading the existing object from the database using the ID, and then binding to this existing object.

              Best regards,

              Comment


              • #8
                In our app, we use a callback mechanism to allow the web tier to do lazy-loading of an object graph when it needs to. The method that performs the callback runs within a transaction/session. Although the web tier doesn't need to know that.

                Comment


                • #9
                  Originally posted by rhasselbaum
                  In our app, we use a callback mechanism to allow the web tier to do lazy-loading of an object graph when it needs to. The method that performs the callback runs within a transaction/session. Although the web tier doesn't need to know that.
                  This is fine within the View, if you're loading a fresh object first.
                  But in the controller, if you're using Hibernate anyway, you can easily run into an error saying something like "attempt to reconnect an object with dirty collections" (I don't remember the exact wording).
                  This is because before loading the collection, you have to reconnect the object to the current session using:
                  Code:
                   this.getHibernateTemplate().lock(entity, LockMode.NONE);
                  If you lazy-load one collection first, modify the collection in any way, and then lazy-load another collection, you'll get the error.

                  Comment


                  • #10
                    Why do you create a new (empty) object after the submit? That's where your problem is. You should be loading the existing object from the database using the ID, and then binding to this existing object.
                    And if you are using optimistic locking you should store the object in the HTTP session before rendering the form page, get it from the HTTP session upon submit and attach to a session ASAP, update the object based on the values returned from the form and only then will you get a concurrent update exception.

                    When you store the object in the HTTP session you should generate a unique id - for example a UUID, store the object in the HTTP session using that id and pass the id as a hidden value instead of the database identity of the object.

                    Comment

                    Working...
                    X