These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 8 posts ] 
Author Message
 Post subject: How to model a polimorphic association? Advices needed
PostPosted: Thu Apr 27, 2006 9:25 am 
Newbie

Joined: Thu Apr 27, 2006 4:56 am
Posts: 12
Imagine this case.

I've got several domain objects, such as User, Item, Collection, Review, Comment, Vote, etc...

In my application happens that a single object is associated with several very different objects. This association is therefore mandatory, unidirectional, and polimorphic by nature, since this object can be associated with different type of objects each time.

For example, a Comment can be expressed on Items, Reviews, Collections, Users. The same goes for Vote, for example.

Of course I want comment to maintain a reference to the 'commented' item, or 'vote' to maintain a reference to the voted item, and I don't want to split the vote or comment class into several specific subclasses (ItemVote, ReviewVote, etc..) because this would complicate my DOM too much and would be overkill.

I don't stricly need the other way around insteas: no enforced need to maintain references from an item to the comments regarding it, or from a item to the votes regarding it. I can leave these out and use service methods to get all the votes for a specific item or the like, by proper HQL queries.

So

Comment ---> Review OR Item OR User OR Collection
Vote ---> Review OR Item OR User OR Collection
etc...

But... how to represent this polimorphic unidirectional association then?

I could use several lookup tables, one for each 'commentable/votable' item, or I could use one big lookup table, with a specific field to identify which table to lookup for finding the wanted instance of the related object, for example:

CommentsCommentable
long commentID
long commentableID
enum (or any other better type) commentableType

so commentableType would tell where to go (which table) to find the involved commentableID.

But I've never seen this in any example of hibernate, nor I can't find on the documentation (manual, etc...) any way to do this.

Is it possible at all with the XML declarative configuration? Is it possible by extending/implementing some HibernateAssociationAbstract class or the like, to provide custom association loading for that very specific case, without having to do all the ORM for the involved objects manually?

Is there another better performant, easier solution, I haven't thought of?

Thanks for any reply =)


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 27, 2006 11:42 am 
Regular
Regular

Joined: Wed Aug 25, 2004 6:23 am
Posts: 91
I think that what you are looking for is the 'any' mapping - take a look here: http://www.hibernate.org/hib_docs/v3/re ... anymapping


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 27, 2006 2:02 pm 
Newbie

Joined: Thu Apr 27, 2006 4:56 am
Posts: 12
r1ch wrote:
I think that what you are looking for is the 'any' mapping - take a look here: http://www.hibernate.org/hib_docs/v3/re ... anymapping


Quote:
The <any> mapping element defines a polymorphic association to classes from multiple tables.


Wow, sounds just right for my case! Wonderful, thanks r1ch, you earned a credit!

Quote:
This type of mapping always requires more than one column. The first column holds the type of the associated entity. The remaining columns hold the identifier


Ok, fine, this seems reasonable. In fact, this was exactly as I inteded to do it 'manually'.

Quote:
It is impossible to specify a foreign key constraint for this kind of association, so this is most certainly not meant as the usual way of mapping (polymorphic) associations. You should use this only in very special cases (eg. audit logs, user session data, etc).


Hum... ugh, this hurts, but I guess that it's quite normal not to be able to have DB foreign keys, since this is an association to multiple tables.

The last sentence warns me though: is there any reason not to this in my case? Are there better, less 'extreme', ways to do this?

This seems like the right thing I need, but that last sentence seems really "avoid to do this at all costs", so I'm doubtful.

Any advice?


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 27, 2006 3:04 pm 
Newbie

Joined: Thu Apr 27, 2006 4:56 am
Posts: 12
Even better, I found out that I can use "Table per concrete class" with explicit polimorphism (opposed to implicit polimorphisms, as was with the <any> mapping), which is the nearly the same, but seems to be better, since it shares the ID through the subclasses tables, and therefore avoid to use a 'discriminator' column for telling which table to query.

Read about this here: http://www.hibernate.org/hib_docs/v3...bleperconcrete

You can even define the super-class as abstract, and this effectively eliminates the need for a common table, and is very very similar to our proposed approach (one table for each object with implicit polimorphism through <any> mapping), the only difference is that instead of using a discriminator value for looking up the object (which allows us to know the table to query in advance), they use a 'shared' ID, where an ID is unique across the N tables, and therefore the ID itself defines the linked object.

Advantages:
* Simpler approach, no discriminator column
* full hibernate support (no limitations as with the <any> mapping, which limits several hibernate features as Polymorphic joins and Outer join fetching)

Disadvantages
* Performances (will have to query across the N involved tables I guess)
* Shared ID (which is less optimal than a proper separate ID for each table)

I'm now wondering if the fact that the DB will need to look for the needed IDs in three different tables (at least that's what I think), not knowing in advance which contains it, adds a lot of performance overhead to the join operations... will have to do some tests about it.

Anyone has experience regarding association to an interface (as my case) and the best way to map this? Implicit polimorphism with <any> mapping or explicit polimorphism with <union-subclass>?

Thanks again for any answer.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 27, 2006 3:15 pm 
Newbie

Joined: Thu Apr 27, 2006 4:56 am
Posts: 12
I searched a bit more, and the union-subclass mapping seems to use SQL UNIONs when making up the query (DOH!), and therefore uses a single (bigger) query to select the data from the union of the involved tables.

This is probably quite efficient, if the DB implements unions efficiently (as most do), and therefore the performance impact shouldn't be very harsh.

And we get to keep all the cool hibernate features! Good to know, and that's maybe because the <any> mapping was so discourages. It *IS* a 'last resort' feature after all ^_^


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 27, 2006 3:28 pm 
Newbie

Joined: Thu Apr 27, 2006 4:56 am
Posts: 12
Still have a doubt about the explicit polimorphism approach through the union-subclass mapping.

Will this allow me to have a class defined as an union-subclass for several abstract classes?

Because my classes implements SEVERAL interfaces (at least two: Votable and Commentable), and I'll need to be able to use them in several union-subclass mapping, one for each of the interface they implement.

Will dig into the documentation to find out, if someone knows, please let us know as well :)


Top
 Profile  
 
 Post subject: My Idea
PostPosted: Thu Apr 27, 2006 4:12 pm 
Regular
Regular

Joined: Wed Feb 22, 2006 11:28 am
Posts: 65
Location: Santiago, Chile
Hello Friend:

I saw you have no care about HQL performance with your solution, You can solve your problem as like as your post, but I suggest you think in the future use of these Objects for HQL. With <any>, you can not do HQL easely. With Subclass, is a major solucion.

I have the same case. I use a solution OO (Oriented Object).

public class Comment {..} <-- It can be abstract

public class Item extends Comment {
public String attribute1;
}
public class Review extends Comment {
public String attribute2;}

You may implement a class called with any name and they include one Comment;

public class Text{
public Comment coment;
}

so, in your Hibernate Mapping file, you define a discriminator value and use it to distinct which of those Object to instance, like:

<class name="Text">
<subclass discriminator-value="item" name="comment" class="Item">
...
</subclass>
<subclass discriminator-value="review" name="comment"
class="Review">
..
</subclass>

</class>


Then, when you can wrote and compile and ejecute the program without any problem (if you do it good with all details):

Text x = (Text)session.get(Text.class, new Integer(12));
if (x.getComment() instanceof Item)
...
else
...

In your HQL, you can wrote:

select c.comment.attribute1 from Text c <-- when you assurance the query is doing for "Item".

select c.comment.attribute2 from Text c <-- when you assurance the query is doing for "Review".


So, you can see the great advantage with "subclass" use, it is very good for performance and HQL.

Request for comments.

Neketsu Shonen


Top
 Profile  
 
 Post subject:
PostPosted: Fri Apr 28, 2006 1:20 am 
Newbie

Joined: Thu Apr 27, 2006 4:56 am
Posts: 12
You are indeed right, but the problem is that I have SEVERAL interfaces that I would like the subclasses to implement at the same time

Interface A
Interface B
Interface C

Class C implements A, B, C
Class D implements B, C
Class E implements A, C

So union-subclass or subclass or the like are NOT applicabile I think, because they can't be used for multiple overlapping hierarchies.

The only viable solution is <any> mapping, which, yes, will cause me to lose a lot of easiness when quering through HQL unluckily.

But I cannot see a better usable solution unluckily. Am I right?


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 8 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.