views:

764

answers:

3

Hi,

I have 3 non-abstract persist-able classes. MyClubUser and HisClubUser classes inherit from User class. I use one table per subclass strategy i.e. @Inheritance(strategy = InheritanceType.JOINED), for these classes.

What I have observed was the generated SQL uses left outer join HisClubUser and MyClubUser when I do a query on User class. Why Hibernate does that [joining other tables] where my concern is only User? My point is even though the data is retrieved, I would not able to access these properties in MyClubUser or HisClubUser given that User instances are returned. Also, does this causes additional overhead as compared to a query where it just query User table without the left outer join?

Thanks

+2  A: 

You query on User, so Hibernate will execute a 'polymorphic query'. Since MyClubUser and HisClubUser are User objects by nature (they inherit from User), Hibernate will retrieve these kind of users as well.

Frederik Gheysels
+3  A: 

Why Hibernate does that [joining other tables] where my concern is only User?

Because all HisClubUser are also valid instances of User, it is logical to retrieve these when you ask for User.

My point is even though the data is retrieved, I would not able to access these properties in MyClubUser or HisClubUser given that User instances are returned.

Are you really sure? Check (in debug for example) the effective class that is returned, it should be the subclasses. So down-casting could be possible, and the properties could be accessed.

Also, does this causes additional overhead as compared to a query where it just query User table without the left outer join?

Yes, and extra join has an overhead. It could be important or not : I suggest you test it in your specific case.

KLE
+1. However, you should probably remove your SimpleUser suggestion as it will not help; I've explained "why" in my answer.
ChssPly76
@ChssPly76 Thanks. I've read your answer, and now I understand precisely the "why". You are right :-)
KLE
Thanks guys... I understand now. What I am doing now is MyClubUser and HisClubUser will have a 1 to 1 relationship with User instead of inherit from User. To access the additional properties in MyClubUSer and HisClubUser I will query again. User is for login. Most of the time the the specific classes are used. Occasionally, properties in User are read.@KLE I am sure. The query only returns User which makes sense. If down casting is possible, then User has to inherit MyClubUser and HisClubUser which is not possible.
thlim
+3  A: 

Hibernate ALWAYS returns the actual type of persisted entity. If you've stored "MyClubUser" it will be returned as "MyClubUser", never as "User". The reason for this is quite clear - if Hibernate were to return "MyClubUser" as "User" and you were to persist it again you would lose all additional properties defined in "MyClubUser".

In order to do that, Hibernate needs to know what that actual type is. For InheritanceType.JOINED strategy the only way to find that out is to check all the tables in your inheritance hierarchy (well, technically it's all tables at or below current level plus all tables above current level in current tree branch). So, if you have a hierarchy like:

           Root
          /   \
      Node1  Node2
      /   \
   Node11 Node12

and you're trying to select from root, Hibernate will do an outer join on ALL tables. If you're selecting from Node1, Hibernate will do an inner join on Node1 and Root plus an outer join on Node11 and Node12. Node2 won't be touched because it's not a descendant of Node1.

As far as outer join overhead goes - yes, there's definitely an overhead but that's the price you pay for joined strategy. You can use discriminators to avoid this but that comes with its own side effects. Whether that overhead is significant or not depends on the depth and spread of your hierarchy, your indexes and many other things. Listen to KLE's suggestion and profile it.

ChssPly76
+1 Thanks a lot for these details, they made clear why my original SimpleUser proposal didn't work with InheritanceType.JOINED. I removed that part from my answer, not to mislead anyone.
KLE