Results 1 to 6 of 6

Thread: Taking advantage of Hibernate 'fetch' select

Hybrid View

  1. #1
    Join Date
    Aug 2004
    Location
    Sydney
    Posts
    503

    Default 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. #2
    Join Date
    Aug 2004
    Location
    San Francisco
    Posts
    423

    Default

    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

    Quote 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,

  3. #3
    Join Date
    Dec 2005
    Location
    Argentina
    Posts
    73

    Default

    You might want to take a look at:

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

    for a discussion on this topic.

    Federico.

  4. #4
    Join Date
    Aug 2004
    Location
    Sydney
    Posts
    503

    Default

    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.

  5. #5
    Join Date
    Aug 2004
    Location
    San Francisco
    Posts
    423

    Default

    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

    Quote 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.

  6. #6
    Join Date
    Nov 2008
    Posts
    9

    Default

    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

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •