-->
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.  [ 3 posts ] 
Author Message
 Post subject: best strategy for inheritance
PostPosted: Tue Jul 29, 2008 6:37 am 
Newbie

Joined: Fri Jul 18, 2008 6:48 am
Posts: 5
hi there,

we are after a little advice if possible. we are trying to build a generic, extensible, community-ish framework, and part of that is the desire to make certain elements commentable - ie people can leave comments on pictures, images, forum posts, etc etc. however, as it is a framework, we will need to extend this functionality to make the actual system (which might, for example, have 'books' that people can comment on). we're using annotations, as they rock.

this is proving quite difficult to understand so i hope someone here might be able to enlighten us as to the best approach.

basically, we have a class Comment, which has a 'text' field, a 'user' field, and a 'parent' field (that points to the object that has been commented on). the object itself (eg Video) has a List<Comment> that holds the comments for the video/whatever. All commentable objects implement an interface ICommentable.

we have tried the following approaches with the following problems (using Video as an example of a commentable object) :

a) Comment is a single class, which has a many-to-any association to parent. here is the code that implements this :

(in Comment.java)
Code:
@Any(fetch = FetchType.LAZY, metaColumn = @Column(name = "item_type"))
@AnyMetaDef( idType = "long", metaType = "int", metaValues = { @MetaValue(targetEntity = Video.class, value = Video.LINKAGEIDENTIFIER) } )
@JoinColumn(name = "item_id")
public ICommentable getParent() {
   return parent;
}


(in Video.java)
Code:
public static final String LINKAGEIDENTIFIER = "1";

@OneToMany
@Fetch(FetchMode.SUBSELECT)
@LazyCollection(LazyCollectionOption.EXTRA)
@Where(clause = "item_type=" + LINKAGEIDENTIFIER)
@JoinColumn(name = "item_id")
@Cascade( { org.hibernate.annotations.CascadeType.DELETE_ORPHAN, org.hibernate.annotations.CascadeType.SAVE_UPDATE, org.hibernate.annotations.CascadeType.PERSIST, org.hibernate.annotations.CascadeType.MERGE })
public List<Comment> getComments() {
   return comments;
}


as you can see, this is far from ideal, as we need to have these LINKAGEIDENTIFIERs (or some other way to do that, such as an enum), and also there is a requirement for the @Where clause, which is messy.

aside from that, this does work, but for the problem that we'd like to extend the system to handle new objects (eg Book) - how to add these new metaValues to the @AnyMetaDef?

b) creating a table-per-class-heirarchy for Comment, making simple subclasses such as VideoComment :

(Comment)
Code:
@Entity
@Table(name = "comment")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="type", discriminatorType=DiscriminatorType.STRING)
public abstract class Comment extends BaseEntity {
...
@Transient
public ICommentable getParent() {
   return parent;
}


(VideoComment)
Code:
@Entity
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class VideoComment extends Comment {
...
@Override
@ManyToOne(fetch = FetchType.LAZY, targetEntity = Video.class)
@JoinColumn(name = "parent")
public ICommentable getParent() {
   return super.getParent();
}


(Video)
Code:
@OneToMany(mappedBy = "parent", fetch = FetchType.LAZY)
@Cascade( { org.hibernate.annotations.CascadeType.DELETE_ORPHAN, org.hibernate.annotations.CascadeType.SAVE_UPDATE, org.hibernate.annotations.CascadeType.PERSIST, org.hibernate.annotations.CascadeType.MERGE })
public List<VideoComment> getComments() {
   return comments;
}


this works really nicely, but as soon as there is more than one type of comment (eg ImageComment) then hibernate tries to generate a foreign key constraint on the 'parent' column to BOTH image.id and video.id which means that inserting any row is likely to fail with foreign key constraint violation.

c) attempting to make the entire object heirarchy use inheritance (not just the comment section) - so Video, Image, Book, etc all inherit from something. this is undesirable because all of the strategies are inefficient for 'normal' access (eg having a BaseEntity table that simply has the id and discriminator value - this would double the time it takes to create a normal object)

so, have we been barking up the wrong tree? are any of these strategies changable so they work as we would like? or is there a better idea out there? :)

thanks in advance
chris


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jul 29, 2008 8:55 am 
Regular
Regular

Joined: Wed Jan 11, 2006 12:49 pm
Posts: 64
Location: Campinas, Brazil
Do you really need the "parent" property from the base comment class? Particularly, I would try to either remove it completely or first try to map it only in the child classes. Or make the ICommentable an abstract entity and stablish a concrete relationship.

From Hibernate docs on any mapping:
"It is impossible to specify a foreign key constraint for this kind of association"

You are getting an FK because you have overridden the "parent" relationship in a single-table inheritance strategy. You should either change the inheritance strategy, rename the column name in the child classes or not override the relationship. Instead, just change the return type "parent" property.

_________________
Henrique Sousa
Don't forget to rate useful responses


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jul 29, 2008 10:20 am 
Newbie

Joined: Fri Jul 18, 2008 6:48 am
Posts: 5
thanks for the reply - yeah we do need the parent property (since we want to also list all comments by a user, and what they relate to)

i'll have a look at making the icommentable abstract, but the trouble is we're going to have IRatable and IReportable too, and multiple inheritence is ugly (and impossible in java) :(

what MIGHT work is convincing hibernate NOT to define a FK constraint on the parent field, since the parent object is always lazy loaded, by the time it comes to that, the correct Comment type will have been instantiated and should be able to load the correct parent type from id only - but with the FK constraint, the database itself just won't allow inserts where the FK constraint doesn't fit :(

i guess the other solution you provide is worth trying - just have parent as an id, and provide another method to get the parent class - eg

int getParentId();

@transient
Class getParentClass();

so we can pass those 2 pieces of info to hibernate to load the parent - but that's getting a little too 'hacky' for my liking :P

thanks for the answer anyway, any other ideas also welcome!

chris


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 3 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.