-->
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.  [ 18 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: How to add additional columns in <many-to-many> table?
PostPosted: Sun Dec 14, 2008 5:43 am 
Newbie

Joined: Thu Jan 31, 2008 8:13 am
Posts: 10
Location: Poland
Hello guys!

I am a newbie to HIbernate, so please forgive me if the question, I'm about to ask, seems a little silly.
I have two classes which I would like to associate using "many-to-many" relationship (these classes are: Exercise and UserTraining). While doing so, the HIbernate will generate a "intermediate" table dor the relationship (let's call it: ExercisesSet). The ExercisesSet consists of two foreign keys from both previous tables.
Now, I would like to add one column to the ExercisesSet table, cause I need to add third Foreign key (representing a day, in this particular example).

This is what I'm trying to achieve:

Image


My questions are:
1. How can I do that in my mapping files?
2. Or maybe, do I have to create a third mapping for my ExercisesSet table?
3. Is there a possibility of adding this third column as a column of type other than ForeignKey (VARCHAR or TIMESTAMP for instance)?

Hibernate version: 3.3.1.GA

Best regards,
Bat

P.S. Question #3 is very important for me, cause I have this kind of an issue in my project as well.

_________________
Kind regards,
Łukasz Bachman


Top
 Profile  
 
 Post subject:
PostPosted: Mon Dec 15, 2008 2:09 am 
Newbie

Joined: Tue Nov 18, 2008 6:08 am
Posts: 14
so you have to design the intermediate table(POJO) by your self,
which will be having CompositeId(Object) and your 3rd column dayId. Here CompositeId is another POJO with the primary keys of both the tables (UserTraining, Excercise).

and the mapping of the intermediate table will be required.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Dec 16, 2008 3:30 am 
Newbie

Joined: Tue Dec 16, 2008 3:25 am
Posts: 1
Hey ,
I am new to hibernate. So can i have some code example?




rudradutt wrote:
so you have to design the intermediate table(POJO) by your self,
which will be having CompositeId(Object) and your 3rd column dayId. Here CompositeId is another POJO with the primary keys of both the tables (UserTraining, Excercise).

and the mapping of the intermediate table will be required.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Dec 16, 2008 4:11 am 
Senior
Senior

Joined: Wed Sep 19, 2007 9:31 pm
Posts: 191
Location: Khuntien (Indonesia)
slrosh wrote:
Hey ,
I am new to hibernate. So can i have some code example?




rudradutt wrote:
so you have to design the intermediate table(POJO) by your self,
which will be having CompositeId(Object) and your 3rd column dayId. Here CompositeId is another POJO with the primary keys of both the tables (UserTraining, Excercise).

and the mapping of the intermediate table will be required.


You can try this link

http://boris.kirzner.info/blog/archives/2008/07/19/hibernate-annotations-the-many-to-many-association-with-composite-key/


Top
 Profile  
 
 Post subject:
PostPosted: Tue Dec 16, 2008 4:34 pm 
Newbie

Joined: Thu Jan 31, 2008 8:13 am
Posts: 10
Location: Poland
Okay, so I guess You were right. I've created an additional POJO called "ExercisesSet" which implements Serializable interface and overrides hashCode() and equals() methods (I've generated those using Commonclipse).

My mappins is as follows:
Code:
<hibernate-mapping>
  <class name="pl.eightyseven.sportfreaks.core.model.ExercisesSet" table="exercises_sets">
    <composite-id>
        <key-many-to-one name="training"   column="training_id"/>
        <key-many-to-one name="exercise"    column="exercise_id"/>
        <key-many-to-one name="day"       column="day_id"/>
    </composite-id>
  </class>
</hibernate-mapping>


I've also prepared JUnit tests, and all of them (saving & loading) work fine accept of the one with removing an ExercisesSet from database. I'm getting the following exception:

Code:
java.lang.NullPointerException
        at org.hibernate.type.AbstractType.getHashCode(AbstractType.java:136)
        at org.hibernate.type.AbstractType.getHashCode(AbstractType.java:144)
        at org.hibernate.type.EntityType.getHashCode(EntityType.java:312)
        at org.hibernate.type.ComponentType.getHashCode(ComponentType.java:212)
        at org.hibernate.engine.EntityKey.generateHashCode(EntityKey.java:126)
        at org.hibernate.engine.EntityKey.<init>(EntityKey.java:70)
        at org.hibernate.engine.StatefulPersistenceContext.getDatabaseSnapshot(StatefulPersistenceContext.java:263)
        at org.hibernate.engine.ForeignKeys.isTransient(ForeignKeys.java:212)
        at org.hibernate.event.def.DefaultDeleteEventListener.onDelete(DefaultDeleteEventListener.java:102)
        at org.hibernate.event.def.DefaultDeleteEventListener.onDelete(DefaultDeleteEventListener.java:74)
        at org.hibernate.impl.SessionImpl.fireDelete(SessionImpl.java:793)
        at org.hibernate.impl.SessionImpl.delete(SessionImpl.java:771)
        at pl.eightyseven.sf.core.dao.hibernate.ExercisesSetDaoHibernate.removeExercisesSet(ExercisesSetDaoHibernate.java:41)


My Hibernate code, in which exception occurs, is as follows:
Code:
public boolean removeExercisesSet(ExercisesSet es) {
      try {
         Session session = sessionFactory.openSession();
         Transaction tx = session.beginTransaction();         
         session.delete(es);   // <----- this is the unfortunate, 41st line of code
         tx.commit();
         return true;
      } catch (Exception e) {
         e.printStackTrace();
         return false;
      }
   }


I'm pretty sure that problem is somehow related to my hashCode() function, but I cannot understand it, since I've tried to simply set the returnig value of hashCode() to zero, and I'm still getting NULL pointer Exc.

Any ideas? Maybe I've skipped something in my mapping, which causes Hibernate to crash?

-------------- Update ----------------
Actually, I have missed one thing. I have only generated one POJO (and mapping) for my intermediate table, but didn't create it for the Primary Key. I didn't think that was necessary since I am holding only those 3 Foreign Keys inside my table, without any other data. Maybe that is, what causes the problem?

_________________
Kind regards,
Łukasz Bachman


Top
 Profile  
 
 Post subject:
PostPosted: Wed Dec 17, 2008 2:20 am 
Newbie

Joined: Tue Nov 18, 2008 6:08 am
Posts: 14
whats your POJO???
& did you try Update also ??


Top
 Profile  
 
 Post subject:
PostPosted: Wed Dec 17, 2008 2:49 am 
Newbie

Joined: Thu Jan 31, 2008 8:13 am
Posts: 10
Location: Poland
No, I haven't tried the UPDATE. What exactly do You mean?

Here's my POJO:

Code:
public class ExercisesSet implements Serializable{
   // Due to implementation of Serializable interface, which is necessary
   private static final long serialVersionUID = -3935817400014249520L;
   
   private UserTraining training;
   private Exercise exercise;
   private Constant day;

   // Constructors
   public ExercisesSet() {
   }

   public ExercisesSet(UserTraining training, Exercise exercise, Constant day) {
      this.training = training;
      this.exercise = exercise;
      this.day = day;
   }

   // Overridden methods
   public String toString() {
      return new String("[ExercisesSet] trainingId=" + training.getId() + ", exerciseId=" + exercise.getId()
            + ", day=" + day.getValue());
   }

public int hashCode() {
      return new HashCodeBuilder(-1892571231, -1747383037).appendSuper(super.hashCode()).append(this.training)
            .append(this.exercise).append(this.day).toHashCode();
   }

   public boolean equals(Object object) {
      if (!(object instanceof ExercisesSet)) {
         return false;
      }
      ExercisesSet rhs = (ExercisesSet) object;
      return new EqualsBuilder().appendSuper(super.equals(object)).append(this.training, rhs.training).append(
            this.exercise, rhs.exercise).append(this.day, rhs.day).isEquals();
   }

   // Getters and setters
   public UserTraining getTraining() {
      return training;
   }

   public void setTraining(UserTraining training) {
      this.training = training;
   }

   public Exercise getExercise() {
      return exercise;
   }

   public void setExercise(Exercise exercise) {
      this.exercise = exercise;
   }

   public Constant getDay() {
      return day;
   }

   public void setDay(Constant day) {
      this.day = day;
   }

}

_________________
Kind regards,
Łukasz Bachman


Top
 Profile  
 
 Post subject:
PostPosted: Wed Dec 17, 2008 3:10 am 
Newbie

Joined: Tue Nov 18, 2008 6:08 am
Posts: 14
I asked because I was wondering weather the same problem is there with UPDATE also or not, by the way I dont think there's any issue with hashcode() and equals(). what I found is

A null pointer exception is thrown when:

a) we have a composite key with one of the attributes of the key being an FK to another persistent class.
b) The other persistent class has an ID field whose value is being generated.
c) The instance of the other persistent class is transient (does not yet have an ID)

and try Update also


Top
 Profile  
 
 Post subject:
PostPosted: Wed Dec 17, 2008 5:05 am 
Newbie

Joined: Thu Jan 31, 2008 8:13 am
Posts: 10
Location: Poland
rudradutt wrote:
A null pointer exception is thrown when:

a) we have a composite key with one of the attributes of the key being an FK to another persistent class.
b) The other persistent class has an ID field whose value is being generated.
c) The instance of the other persistent class is transient (does not yet have an ID)

and try Update also


Thanks! I've found the same tips in the internet somewhere.

The thing is, that a) doesn't make any sense for me cause that is pretty common situation in relational databases!
b) this is also normal situation, for sake!
c) in my case the entities (exercise, training, day) ARE persistent, cause I've saved them before creating my ExercisesSet entity. So this case shouldn't have any impact on my issue.

If I won't solve this problem today, I guess i will go for modifying my Database and getting rid of many-to-many relationship. I could do that in the beginning but I wanted to do this the right way. But I'm getting tired of this issue a little since I do not know where the problem lies and I'm guessing this is internal Hibernate bug.

_________________
Kind regards,
Łukasz Bachman


Top
 Profile  
 
 Post subject:
PostPosted: Wed Dec 17, 2008 6:26 am 
Newbie

Joined: Tue Nov 18, 2008 6:08 am
Posts: 14
This is most common situation as you mentioned, so its not a Hibernate bug at all,

I recommend you do as I said earlier,

create a POJO for your Composite Primary key (say CompositeId)
than

create another POJO with
Code:
private CompositeId compositeId;
private UserTraining training;
private Exercise exercise;
private Constant day;

constructors and getters setters.......


and map the above POJO as

Code:
<composite-id name="compositeId" class="compositeId">
        <key-property name="training_id"   column="training_id"/>
        <key-property name="exercise_id"    column="exercise_id"/>
        <key-property name="day_id"       column="day_id"/>
</composite-id>
<many-to-one name="training">
            <column name="training_id" not-null="true" />
</many-to-one>
<many-to-one name="exercise">
            <column name="exercise_id" not-null="true" />
</many-to-one>
<many-to-one name="day">
            <column name="day_id" not-null="true" />
</many-to-one>


and I assure you it will work.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Dec 17, 2008 6:29 am 
Newbie

Joined: Thu Jan 31, 2008 8:13 am
Posts: 10
Location: Poland
Okay, I'll look into it as soon as I'll come back home. If I manage to make it work, I'll try to post the entire solution here.

Best regards.

_________________
Kind regards,
Łukasz Bachman


Top
 Profile  
 
 Post subject:
PostPosted: Wed Dec 17, 2008 1:07 pm 
Newbie

Joined: Thu Jan 31, 2008 8:13 am
Posts: 10
Location: Poland
Okay, after few test I think I'm finally getting somewhere. Not ready to post the entire solution, though.

I've done as You advised (created the POJO for my primary key, corrected the mapping for my ExercisesSet) and my basic CRUD test went OK.

Now, I have a theoretical question (maybe a little off-topic). Since I am creating my PK as composite-id, I am now obliged to assign the necessary FKs myself, right?
What I mean is:
when I have added ExercisesSetPK (my PK class) to ExercisesSet as a private member and corrected the mapping, I received exceptions errors that members of ExercisesSetPK haven't been set. This makes sense, cause I didn't specify any separate mapping for my PK so Hibernate doesn't know were to fetch data from. I'm cool with that :-)
Hibernate also complained that my mapping should include insert="false" update="false" properties, so I have added them as well to my many-to-one tags. After that all worked fine.
Coming back to my previous thought... Since Hibernate asked me to set the values of ExercisesSetPK member before I save my ExerciseSet entity, the only place of doing that which occurred to me was inside my ExerciseSet constructor. That way I will be able to set all FKs when I create new man-to-many relationship. So I have modified my constructor:
Code:
public ExercisesSet(UserTraining training, Exercise exercise, Constant day) {
      this.training = training;
      this.exercise = exercise;
      this.day = day;
      // Setting primary keys properties
      id = new ExercisesSetPK(training.getId(), exercise.getId(), day.getId());
   }


This seems to work al right, but (finaly!) it made to think...
Since ExercisesSet is a base class for my business logic, and a ExercisesSetPK is only being used by Hibernate layer, doesn't that part of code bring those two separate layers too close together?

I mean, I try to make this project as flexible as possible. Maybe in two years from now I would like to get rid of Hibernate and use something else instead? But in this particular class I will have this unnecessary part of code which is related only to the Hibernate and probably I won't be needing that if I decide to jump over to some other ORM engine.

You catch my drift? (is that how You say it in English ?:-) )

Best regards,
Bat

P.S. Maybe this is totally irrelevant from the standpoint of regular Hibernate user, but I really try to learn this engine best, so I need to understand the things I'm doing.

_________________
Kind regards,
Łukasz Bachman


Top
 Profile  
 
 Post subject:
PostPosted: Thu Dec 18, 2008 2:04 am 
Newbie

Joined: Tue Nov 18, 2008 6:08 am
Posts: 14
Please correct me if I am wrong,
I will store my POJO in something like
Quote:
-com.org.model.excercise
+ ExercisesSet.java
+ ExercisesSetPK.java
+ ExercisesSet.hbm.xml

-com.org.dao.excercise
+ ExercisesSetDAO.java


So, Package might have look different for other ORM.
but you are using hbm.xml which is also ORM specific + you are using cfg.xml also is. So not ExcercisesSet only is your base class but the rest of the files in, are also. As ExcercisesSet stands no meaning without them, it is another Object only. So, you are certainly doing no flexible application with Hibernate. yes you can independently select your relational database.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Dec 18, 2008 2:04 am 
Newbie

Joined: Tue Nov 18, 2008 6:08 am
Posts: 14
Please correct me if I am wrong,
I will store my POJO in something like
Quote:
-com.org.model.excercise
+ ExercisesSet.java
+ ExercisesSetPK.java
+ ExercisesSet.hbm.xml

-com.org.dao.excercise
+ ExercisesSetDAO.java


So, Package might have look different for other ORM.
but you are using hbm.xml which is also ORM specific + you are using cfg.xml also is. So not ExcercisesSet only is your base class but the rest of the files in, are also. As ExcercisesSet stands no meaning without them, it is another Object only. So, you are certainly doing no flexible application with Hibernate. yes you can independently select your relational database. ;)


Top
 Profile  
 
 Post subject:
PostPosted: Thu Dec 18, 2008 4:33 am 
Newbie

Joined: Thu Jan 31, 2008 8:13 am
Posts: 10
Location: Poland
Actually my packages look as follows:


pl.proj_name.model
- UserTraining
- Exercise
- Constant (needed for my "day" representation)
- ExercisesSet

pl.proj_name.dao
- ExercisesSetDao

pl.proj_name.dao.hibernate
- ExercisesSetDaoHibernate
- ExercisesSetPK (I've put this here, cause it's meant to be used by Hibernate only)

pl.proj_name.managers
- ExercisesSetManager

pl.proj_name.managers.impl
- ExercisesSetManagerImpl

And all my *.hbm.xml files (and other configuration files) are placed under "resources" directory, not inside my packages. They are copied inside my JAR only if we are using Hibernate. If we decide not to use it, they won't be placed inside the final Release. This is good practice, I guess :-)

This structure, although complicated, helps me to avoid being dependent of any ORM engine (except of that ExercisesSetPK part, which we are discussing). If I want to change the implementation of any DAO, I just edit my Spring beans. But this hard-coded primary key binds my model package with my dao.hibernate package, which I would like to avoid. In the worst case - I can simply not use ExerciseSetPK when I decide to change my dao-implementation layer, but this redundancy remains... ;-)

Once again, I'm just asking about that cause I want to know if I understood the "composite-id case" correctly.

_________________
Kind regards,
Łukasz Bachman


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 18 posts ]  Go to page 1, 2  Next

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.