Sunday, March 21, 2010

FetchType.EAGER - Cannot simultaneously fetch multiple bags

I just came across a quite interesting problem that might give you a hint on how hibernate internally works. Assume you have the following object association:


  • A references B

  • A has a one-to-many relationship with C and the fetch type is set to FetchType.EAGER

  • B has a one-to-many relationship with D and the fetch type is set to FetchType.EAGER



If you try to initialize hibernate using such a layout, you will receive an error message saying something like cannot simultaneously fetch multiple bags.

Since my mappings were okay until I added a test case for B and the relationships of B were correct on first sight, I started to search for a possible reason. I came across different solutions, among them I found this one from Eyal Lupu. It did not directly solve my problem, but let me analyze the code from a different point of view.

Eyal writes, that it is not allowed to have two mapped lists in one entity being marked with FetchType.EAGER because the sql statements generated would lead to an incorrect loading of the desired entity. If you look at my example above, there is just one list per entity to be loaded eagerly, so why does it fail? The solution to that problem is the first statement of my example: A references B.

If you refer from one to another entity without further fetch type definition, hibernate will always apply FetchType.EAGER. That again leads to a join operation between the relations that contain A and B. Since the relationships between A - C and B - D are also marked to be loaded eagerly, they will be incorporated into the sql statement creation as well. Guess what operation will be used to compute the entities of the relationship: JOIN. And that leads us back to Eyals posting.

Eyal suggests to add an @IndexColumn annotation which replaces the bag semantics with list semantics that gives hibernate a hint on how to handle elements of that type. Another solution - and that's the one I chose - is to mark the connection between A and B as begin fetched lazy. In case you need the relationship between A and B being resolved on entity loading, a third solution would be to mark one or both of the one-to-many relationships as being fetched lazy.

Next to the FetchType.EAGER problem it is a good idea to have some of the relationships mentioned in the example above marked as being loaded lazy. Loading all associated objects eagerly and having a relationship that for example represent a chain of ancestors would leave you with a large set of objects loaded although you need just only one.

No comments:

Post a Comment