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.  [ 14 posts ] 
Author Message
 Post subject: FKs nightmare
PostPosted: Fri Jun 15, 2007 4:15 pm 
Beginner
Beginner

Joined: Wed Apr 18, 2007 1:44 pm
Posts: 27
Hi all,

I have asked this a time ago but I got no replies. Since then I've tried a lot of things but without finding out any satisfactory solution. The fact is: I have reviews, I have review targets, these targets are of arbitrary entity classes, the many-to-one association (and its reciprocal) from the review to its target is determined by a pair (id,kind) where kind is mapped one-to-one to the set of target classes (that is, it's a sort of discriminator field). Schematically:

Review:
targetId ------> (references Product.id or Store.id according to targetKind)
targetKind = { "Product", "Store" }

I have tried to implement this on top of:

1) <any> association

2) @Where clause for reviews collections, to restrict results to correct kinds

3) custom @Loader for reviews collections

4) the event system, and completely custom reviews collection management, including cascading.

5) combinations of the above

The fact is that the three first approaches, while being simpler, generates a different FK for each review target class, which of course are impossible to satisfy all at the same time. I could name these FKs with known names and then remove them just after the session factory is created, but besides being a horrible hack, this won't work anyway because the database is not empty and creation of the FKs will fail at the first place. So I'm losing automatic schema update which I want to preserve at all costs.

Approach four of course doesn't generate any FKs because I'm doing everything by myself here and there is no notion of collection from hibernate side. But this is all too cumbersome and the implementation is a bit complicated and fragile.

Is there any way to SELECTIVELY AVOID FK CREATION?

Please, I really need help with this.

Thank you in advance.
Cheers,
Carlos


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jun 15, 2007 4:17 pm 
Beginner
Beginner

Joined: Wed Apr 18, 2007 1:44 pm
Posts: 27
Quote:
generates a different FK for each review target class,


Sorry, I meant a different FK *CONSTRAINT* there.


Top
 Profile  
 
 Post subject: Re:
PostPosted: Fri Jun 15, 2007 6:42 pm 
Senior
Senior

Joined: Tue Jun 12, 2007 4:49 pm
Posts: 127
Location: India
Hi,

It doesn't appear all that complex as long as:

1) there is a base interface for all the entities you would like to map with (id,kind) as primary key.

2) You don't mind following table-per-subclass hierarchy.

Let me know if these are fine and we will have a solution for you :-)

*Do rate if this is helpful*

Regards,
Jitendra


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jun 15, 2007 7:44 pm 
Beginner
Beginner

Joined: Wed Apr 18, 2007 1:44 pm
Posts: 27
Quote:
1) there is a base interface for all the entities you would like to map with (id,kind) as primary key.


There is a base interface ReviewTarget that is itself an Entity<Integer> which provides just an Integer id. So review gets id/kind from the target entity id and from its concrete class, respectively. See that I can't map this to a another schema than table x class (without union), because there isn't a hierarchy rooted at ReviewTarget, of course as it is an interface and additionally because I can't design the app as that at all.

Quote:
2) You don't mind following table-per-subclass hierarchy.


That's my only choice as I have said. The problem is with the generation of FK constraints. I can't see how do you avoid that by simply using table-per-subclass plus a "root" review target interface.

Thank you for your answer.
Cheers,
Carlos


Top
 Profile  
 
 Post subject: Re:
PostPosted: Fri Jun 15, 2007 7:58 pm 
Senior
Senior

Joined: Tue Jun 12, 2007 4:49 pm
Posts: 127
Location: India
http://forum.hibernate.org/viewtopic.php?t=976136

Review my post on this article and see if you can relate to it. Its 5:30 am.. am off to sleep for now. If it does not solve drop a message here and will look at it over the weekend.

cheers!
Jitendra


Top
 Profile  
 
 Post subject: Re:
PostPosted: Fri Jun 15, 2007 8:35 pm 
Beginner
Beginner

Joined: Wed Apr 18, 2007 1:44 pm
Posts: 27
jits_1998 wrote:
http://forum.hibernate.org/viewtopic.php?t=976136

Review my post on this article and see if you can relate to it. Its 5:30 am.. am off to sleep for now. If it does not solve drop a message here and will look at it over the weekend.

cheers!
Jitendra


The problem with polymorphic many-to-any is that it doesn't support the inverse any-to-many, as you can see here http://www.hibernate.org/hib_docs/v3/re ... imitations. And then, as soon as you try to work around this by using one-to-many instead, you get a new FK constraint autogenerated for each one-to-many defined association. Of course everyone of these constraints can't be valid at the same time and you really don't want them there.

Thank you for your answer.
Cheers,
Carlos


Top
 Profile  
 
 Post subject: Re:
PostPosted: Sat Jun 16, 2007 6:57 am 
Senior
Senior

Joined: Tue Jun 12, 2007 4:49 pm
Posts: 127
Location: India
If you have a base interface then you will not need many to any.

It will be a relationship with the interface, i.e. each of the concrete classes will hold many-to-many or many-to-one relationship with the interface as the need be.

It would help better if you can provide more details in your classes, if this does not help.

Regards,
Jitendra


Top
 Profile  
 
 Post subject:
PostPosted: Sat Jun 16, 2007 2:42 pm 
Beginner
Beginner

Joined: Wed Apr 18, 2007 1:44 pm
Posts: 27
Hi,

here are the details:

Code:
///////////////////////// Feedback

class Feedback extends AbstractEntity<Integer> {
   int targetId;
   String targetKind;
   void setTarget(FeedbackTarget target) {
       targetId = target.getId();
       targetKind = classToKind(target.getClass());
   }   
}

class Review extends Feedback {
   ....
}

class Rating extends Feedback {
   ....
}

// Here follows other types of Feedback

///////////////////////// FeedbackTarget

interface FeedbackTarget implements Entity<Integer> {
}

interface Reviewable extends FeedbackTarget {
   void addReview(Review review);
   void removeReview(Review review);
   List<Review> getReviews();
}

interface Rateable extends FeedbackTarget {
   void addRating(Rating rating);
   void removeRating(Rating rating);
   List<Rating> getRatings();
}

abstract class AbstractReviewable extends AbstractEntity<Integer> implements Reviewable {
   ....
}

abstract class AbstractRateable extends AbstractEntity<Integer> implements Rateable {
   ....
}

abstract class AbstractReviewableRateable extends AbstractRateable implements Reviewable {
   ....
}

// Here follows interfaces and abstract classes for other feedback target kinds and their combinations (the last implemented through delegation+composition of simple targets kinds)

// Then the target themselves:

class Product extends AbstractReviewableRateable {
   ....
}

class Store extends AbstractReviewable {
   ....
}

class User extends AbstractRateable {
   ....
}

// Here follows other types implementing FeedbackTarget


The problem with the FKs constraints arises when trying to map the one-to-many relationships of the FeedbackTarget subinterfaces, that is Rateable, Reviewable, etc.

Thank you for your help.
Cheers,
Carlos


Top
 Profile  
 
 Post subject:
PostPosted: Sat Jun 16, 2007 2:42 pm 
Beginner
Beginner

Joined: Wed Apr 18, 2007 1:44 pm
Posts: 27
Removal of duplicated post.


Top
 Profile  
 
 Post subject: Re:
PostPosted: Sat Jun 16, 2007 4:39 pm 
Senior
Senior

Joined: Tue Jun 12, 2007 4:49 pm
Posts: 127
Location: India
Okay, now I can see and understand your problem.

Hibernate or rather any ORM tool tries to be as close in resemblance and concept as possible to the code.

In your case you have a different List for Reviews in Reviewable and for Ratings in Rateable. This tells me that you would like to distinguish between Ratings and Reviews rather than treating them alike as Feedback, so hibernate will also treat them differently.

Similar is the case of Feedback target, if you want them to have a single key you will have to save them as FeedbackTarget interface references. To restrict loading of only allowed type of feedback target by many-to-one references you can restrict them by using where clause.

Let me know if this helps, we can always discuss more.

One thing I am reasonably sure is that there will be no nightmares :-).

Regards,
Jitendra


Top
 Profile  
 
 Post subject:
PostPosted: Sat Jun 16, 2007 6:28 pm 
Beginner
Beginner

Joined: Wed Apr 18, 2007 1:44 pm
Posts: 27
Quote:
In your case you have a different List for Reviews in Reviewable and for Ratings in Rateable.


For the Feedback hierarchy everything is fine as it is. I really don't care to map it to a hierarchy at all, I'm never seeing these collections as polymorphic ones, there are Review collections, there are Rating collections, etc, but not mixed ones. The fact that there is a Feedback superclass is a matter of design that is transparent to hibernate. No problem here.

Quote:
Similar is the case of Feedback target, if you want them to have a single key you will have to save them as FeedbackTarget interface references. To restrict


No, I don't want to have a single key, I don't want to impose any restriction on targets besides being an Entity<Integer> (that is, having an Integer key, which I need to set the pseudo-FK id/kind). So almost any entity could in principle be a target. There is no hierarchy of targets. There are those support abstract classes for dealing with collections of reviews and other feedback types, but that's another story. I'll never treat a target polymorphically, at least from hibernate side.

The simplest scenario I could figure out that still contains the problem is that of my first post:
Code:

class Review extends AbstractEntity<Integer> {
   int targetId;
   String targetKind;
   void setTarget(Entity<Integer> target) {
      targetId = target.getId();
      targetKind = getKindForClass(target.getClass());
   }
   Entity<Integer> getTarget() {...}
}


class Product extends AbstractEntity<Integer> {
   List<Review> getReviews() {...}
}

class Store extends AbstractEntity<Integer> {
   List<Review> getReviews() {...}
}

And that's all. You can see: getTarget() is "many-to-any", while getReviews() is "any-to-many". Please don't think of any hierarchy here, they have nothing to do with the problem. Let's say that Review, Product and Store are just Objects (well, Entity<Integer> which is the minimal requirement to be entities).

Thank you again.
Cheers,
Carlos


Top
 Profile  
 
 Post subject: re:
PostPosted: Sun Jun 17, 2007 7:17 am 
Senior
Senior

Joined: Tue Jun 12, 2007 4:49 pm
Posts: 127
Location: India
Hi,

While hibernate is primarily designed for hierarchy, it appears that you want to "re-use" the tables instead of them having any kind of hierarchy. My understanding stems from the fact that you do not want to use polymorphism at all in hibernate.

One of the approach that comes to my mind is you can try is making use of components in hibernate. Not sure if you have looked them, but they are the closest concept of reuse in hibernate without having any kind of hierarchy.

Another approach that is definitely worth trying is related to using single table per class hierarchy, since there are not too many different columns in the tables. But I am sure you must have looked at them.

But before that you need to start with a clean drawing board and a single line of thought that you are not going to use "any" type of mappings. I do that sometimes and it kind of forces me to try on different things.

Since you have so many tables, having multiple foreign keys between same columns will affect performance of app as well as db, which must have occured to you. My feeling is that your design is not fully consistent. Different mappings tell hibernate you want to distinguish so it will give you different FKs, thats there in stone.

Regards,
Jitendra


Top
 Profile  
 
 Post subject: Re: re:
PostPosted: Sun Jun 17, 2007 2:55 pm 
Beginner
Beginner

Joined: Wed Apr 18, 2007 1:44 pm
Posts: 27
Quote:
While hibernate is primarily designed for hierarchy, it appears that you want to "re-use" the tables instead of them having any kind of hierarchy.


It's more what I need than what I want.

Quote:
Another approach that is definitely worth trying is related to using single table per class hierarchy,


For review targets? That would imply having the 80% of the app inside a table, most of it nulled out. It would be difficult to impose a hierarchy just for the review stuff, that's so for the java side, and no need to say that it's a no-no for the hibernate side.

Quote:
Since you have so many tables, having multiple foreign keys between same columns will affect performance of app as well as db, which must have


There should be no FK at all. Just targetId/targetKind to define the join condition. No FK constraints, that's for sure.

Quote:
occured to you. My feeling is that your design is not fully consistent. Different mappings tell hibernate you want to distinguish so it will give you different FKs, thats there in stone.


It's the simplest design I've worked out for this situation. It's a common pattern also (the pseudo id/discriminator fk), although it goes to some extent against database purisms. I just need to review lots of things, that's a functional requirement. I cannot impose a hierarchy to 80% of the entire app just for review purposes, that's somewhat of a design requirement, to say so. So my reviews just target Objects, well, ReviewTargets, which is more or less of a marker interface, just following a bit of programming by intention here. The only problem I find is the difficult of mapping the design and, of course, that I have to give up the possibility of having target FK constraints, which is a tradeoff I will be happy to take just in case hibernate let me do it.

Thank you.
Cheers,
Carlos


Top
 Profile  
 
 Post subject: re:
PostPosted: Sun Jun 17, 2007 4:13 pm 
Senior
Senior

Joined: Tue Jun 12, 2007 4:49 pm
Posts: 127
Location: India
The problem is stemming from the fact that target.id is actually a primary key, but you do not want that to be treated as a primary key. Because if it gets treated then there is surely going to be an FK.

In short any kind of direct mapping on this table will lead to FK. don't think there is anything in hibernate that will not create an FK if you refer to it as a PK from other table.

The other issue is that there is no linking of the targetKind with any column in db. Since it is not a column, hibernate will have little to do with it.

Another thing that comes to my mind and could be of your rescue is "property-ref" in hibernate. We are using it one of our projects here, its in design stage right now. We have a table which has a long type primary key, along with that there is a unique key on client-id and a column called key. so each client is allowed to have one key entry only once. and we (plan to) refer the record with client+key combination using property-ref, instead of refering to it using primary key, this i guess is not going to give me an FK.

But you have to have any unique key defined on your table that will allow you to use this pattern. See if there can be something. But again since they are going to refer to different tables for different combination, direct support for hibernate will not be there.

Regards,
Jitendra


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