Announcement Announcement Module
Collapse
No announcement yet.
Taking advantage of Hibernate 'fetch' select Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Taking advantage of Hibernate 'fetch' select

    Does anyone have a nice way to take advantage of fetching the parent + child data in one database visit while minimising clutter in the DAO layer?

    e.g.

    session.createQuery("select p from Person p left join fetch p.addresses where p.id = ?", id).uniqueResult();

    will retrieve a single Person and all of their Addresses in a single trip to the DB. So will the following:

    session.createCriteria(Person.class)
    .add(Restrictions.idEq(someId)
    .setFetchMode("addresses", FetchMode.JOIN);


    What's the best approach out of:

    1. Adding additional DAO methods as required which pre-fetch differing amounts of data using HQL, or

    2. Parameterising DAO methods with the additional child data they should retrieve, and possibly using the session.createCriteria approach instead of HQL, or

    3. Other?

    We've currently got a business logic layer and a DAO layer, but seems like adding some additional service/use-case layer might be a good place to handle these considerations. The thing is, you probably still don't want HQL leaking up into any service layer.

    Thanks,

  • #2
    I had to face this situation a few months ago - basically multiple use cases that required the same object but with the associated object graph hydrated to different levels. With a couple of different hydration levels you can get away with a service method for each but this soon gets out of hand once the number starts to grow.

    I came up with a solution in which I pass a hydration specification to the services. Thus, clients of the services are responsible for specifying the hydration level they need. The DAOs are then responsible for creating the required query from these hydration levels. I make my domain objects publish (via public static finals) allowable hydration levels for themselves. This establishes a nice seperation of concerns.

    In addition, the hydration specification is split into two parts - prefetch and postfetch. The DAOs use the prefetch values via the setFetchMode method of criteria (I use criteria's for this) and the post-fetch values via the initialize method of the session. I use OGNL constructs to refer to the specific parts of the object graph. I'm using this method quite successfully in both a web and swing client. As a slight aside, I also prefer to explicitly specify the hydration levels rather than replying on OSIV filters.

    This seems a tad theoretical when I read it, but it's actually quite straightforward once you see the code. A number of other people have asked me for examples of this approach in the past and if you're interested I can forward a small example I've put together.

    Jonny

    Originally posted by gmatthews
    Does anyone have a nice way to take advantage of fetching the parent + child data in one database visit while minimising clutter in the DAO layer?

    e.g.

    session.createQuery("select p from Person p left join fetch p.addresses where p.id = ?", id).uniqueResult();

    will retrieve a single Person and all of their Addresses in a single trip to the DB. So will the following:

    session.createCriteria(Person.class)
    .add(Restrictions.idEq(someId)
    .setFetchMode("addresses", FetchMode.JOIN);


    What's the best approach out of:

    1. Adding additional DAO methods as required which pre-fetch differing amounts of data using HQL, or

    2. Parameterising DAO methods with the additional child data they should retrieve, and possibly using the session.createCriteria approach instead of HQL, or

    3. Other?

    We've currently got a business logic layer and a DAO layer, but seems like adding some additional service/use-case layer might be a good place to handle these considerations. The thing is, you probably still don't want HQL leaking up into any service layer.

    Thanks,

    Comment


    • #3
      You might want to take a look at:

      http://forum.springframework.org/showthread.php?t=22090

      for a discussion on this topic.

      Federico.

      Comment


      • #4
        Thanks for the responses.

        Both posts were very helpful.

        I was just wondering with the post from jwray, if you're build a web app only (using OSIV), is there any benefit from doing the post-fetch stuff.

        Hibernate will do less trips to the DB if you "fetch" join your query, but I'm not aware of any efficiencies of doing Hibernate.initialize over just using OSIV.

        Do you know of any?

        Its arguably the case that the approach you've suggested should probably be best-practice for DAO objects, i.e. passing in a HydrationSpecification to minimise the number of methods, that vary only by the part(s) of the object graph they load.

        Comment


        • #5
          For sure, I don't think there are any efficiencies of using post fetch initializes over OSIV. At least I can't think of any. For a web app only you could probably get away with passing in the prefetch specifications and letting OSIV do the rest.

          I went that route for a more than one reason.

          I was bitten with OSIV a couple of times and was fighting to get it to work in some cases. On top of that my DAOs were starting to get crowded with multiple methods that differed only by their degree of hydration and, finally, I needed a remote interface. Of course, these reasons didn't happen all at once but they built up until I got to the point of the solution I previously outlined.

          Also, after using this solution for a while I found that having to explicitly specify my hydration levels forced me to think about what data was needed for a particular use case, which data could be prefetched etc., and this is a good thing. Using OSIV I found I could easily produce an N+1 performance problem.

          On top of all this, I find my current solution has a clean seperation of responsibilities between the DAOs, the domain objects and the clients of the services, which makes the code easier to understand and maintain.

          Jonny

          Originally posted by gmatthews
          Thanks for the responses.

          Both posts were very helpful.

          I was just wondering with the post from jwray, if you're build a web app only (using OSIV), is there any benefit from doing the post-fetch stuff.

          Hibernate will do less trips to the DB if you "fetch" join your query, but I'm not aware of any efficiencies of doing Hibernate.initialize over just using OSIV.

          Do you know of any?

          Its arguably the case that the approach you've suggested should probably be best-practice for DAO objects, i.e. passing in a HydrationSpecification to minimise the number of methods, that vary only by the part(s) of the object graph they load.

          Comment


          • #6
            Hi, since this thread pops up in various searches, just wanted to note that Hibernate 4 allows to solve this problem using:

            Code:
            @FetchProfile(name = "customer-with-orders", fetchOverrides = {
               @FetchProfile.FetchOverride(entity = Customer.class, association = "orders", mode = FetchMode.JOIN)
            })
            See http://docs.jboss.org/hibernate/core...ching-profiles

            Comment

            Working...
            X