Showing posts with label JAVA. Show all posts
Showing posts with label JAVA. Show all posts

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.

Friday, August 21, 2009

FileUpload with Richfaces

The other day I had an assignment to write a CSV upload and download interface for a JSF (Richfaces) based web application. On first sight, that isn't a really tricky task since it was realised many times before by a lot of people - including me. Therefore I was quite confident to implement that feature quite quickly ... until it came to the point where I tried out what I implemented. Unfortunately, the file was not uploaded although my code wrote the correct filename to the log output. This is my sourcecode:

public void uploadListener(final UploadEvent uploadEvent) {
UploadItem uploadItem = uploadEvent.getUploadItem();
String fileName = uploadItem.getFileName();
String csvFile = new String(uploadItem.getData());
...
}

The method signature follows the requirements set by richfaces in order for a method to receive incoming upload events. Usually the upload item variable should contain all required information, especially the required file data.

The reason why the upload item is not filled as expected, is the AJAX filter option createTempFile which is set to true by default. Under these circumstances the uploaded file data will not be made available to the upload item variable, but is written into a temporary file on disk. To change this behavior, its necessary to switch the config option of org.ajax4jsf.Filter to true in the web.xml.