Tuesday, February 9, 2010

n+1 select & fetch strategy

The n+1 select is for return *LIST* of objects, and the object contains collection. Then we can use 'subselect' fetch strategy to reduce the number of queries. For example, Template (1-->*) DeployedController, with default fetch strategy 'select', to return a list of template it requires 1 + n selects.


select * from template;
select * from deployedController where templateId=?
select * from deployedController where templateId=?
...

With 'subselect', it becomes only 2 queries -

select * from template;
select * from deployedController where templateId in (select id from template)

This is for lazy loading, the 2nd query is run when the 1st time the deployedController collections is accessed. For eager loading, change fetch strategy to 'join', then only one query (left outer join) is used but the resultset contains duplicate or null values.

The subselect option is currently only available for collection, not for *-->1 assocation.

Eager loading:
1. lazy="false", stands for fetch="select", follow by an immediate second select
2. fetch="join"
Lazy Loading:
1. fetch="subselect"
2. batch-size="N"

Thursday, February 4, 2010

Common Hibernate Exceptions

1. a different object with the same identifier value was already associated with the session
In session cache, a persistent object exists uniquely. To avoid this exception, use merge() instead of saveOrUpdate().

One example, many-to-one between authRadius->radius, and I have authRadiusSet[authRadius1(radius1), authRadius2(radius2)], here radius1 and radius2 actually have same database identifier but different objects. When I tried to save authRadiusSet, I got this exception.

2. Duplicate entry '1' for key 2
The object tree for cascade save/update contains two objects with same object id (java object).

3. A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance
What is happening here is that Hibernate requires complete ownership of the preferences collection in the User object. If you simply set it to a new object as in the above code sample, Hibernate is unable to track changes to that collection and thus has no idea how to apply the cascading persistence to your objects! So either user.setPreferences(new HashSet()) or user.setPreferences(null) will cause such error. This is also a reason to provide helper methods such as addPreference() and removePreference() to avoid setPreferences is called (made private). See ...

4. Found shared references to a collection org.hibernate.HibernateException
It throws when session flush. It is due to one collection referenced by two entities. To relove it, use merge().

5. TransientObjectException
The object graph to be persisted cannot contains any transient objects (id != 0) without cascade defined. Also note that, if it contains detached object (id >0) and no cascade defined, the detached object will be deleted upon persisting.

6. ObjectDeletedException
Deleted object would be re-saved by cascade. It occurs when you move one object from one collection to the other and you have 'delete-orphan'. There is not good solution.
https://forum.hibernate.org/viewtopic.php?t=981282

Wednesday, January 27, 2010

enum != Enum

All enumerations automatically contain two predefined methods: values( ) and valueOf( ).

1. public static enum-type[ ] values( )
2. public static enum-type valueOf(String str)

These two methods are not in Enum API.


enum Week {
Monday, Tuesday, Wednesday, Thursday, Friday, Saturaday, Sunday
}

Week allWeek[] = Week.values();

Wednesday, January 20, 2010

Bag vs. List


public class FilterGroup {
private List<Fitler> filters = new ArrayList<Fitler>();
...
}








I mapped List as above but got bizarre result. Although there are only 8 items in the list, it returned a list with over 1000 item and most of them are null. It turns out this is because the column "orderPos" used for list index contains a big number 1025+.

I do want a sorted list. So I change to use bag mapping with order-by. It works well. In Hibernate document, it said bag is mapped for Collection. Internally it is implemented as ArrayList but ignores index (Bag is different from set in that it allows duplicates). So I can map it to List as well and add a order-by to sort it in database level. (set, map, bag all can have order-by)






Also, note that we need "delete-orphan" cascade for collection. So when we do a update on FilterGroup, the filters removed from the collection will be deleted from database automatically. Otherwise, it will still remain.