mosa wrote:
Hi,
The way Hibernate handles many-to-many to associations is by creating a middle table implicitly without you having to explicitly define one in the mapping file. This has the downside that you can’t define additional properties/columns in that middle table as you don’t have a handle at a POJO level.
If you would like to define additional columns in the middle table (like in your case) then you have to use two one-to-many relationships for both sides and explicitly map that in an .hbm file. This will give you a handle at a POJO level to play with.
mosa
Thanks for this. I have now created a class for the mapping table as follows:
public class MovieActor implements Serializable{
public static class Id implements Serializable{
public Long movieId;
public Long actorId;
}
private Id id;
private String character;
private Movie movie;
private Actor actor;
public Id getId() {
return id;
}
public void setId(Id id) {
this.id = id;
}
// ......
}
<hibernate-mapping package="com.drew.entities">
<class name="MovieActor" table="movies2actors">
<composite-id name="id" class="MovieActor$Id">
<key-property name="movieId" column="movieid" access="field" />
<key-property name="actorId" column="actorid" access="field" />
</composite-id>
<!-- Relationships Begin here -->
<many-to-one name="movie" class="Movie" insert="false" update="false" />
<many-to-one name="actor" class="Actor" insert="false" update="false" />
<!-- Relationships End here -->
</class>
</hibernate-mapping>
and changed the movie (and similarly for actor) mapping to:
<hibernate-mapping
package="com.drew.entities">
<class name="Movie" table="movies">
<id name="id" column="movieid">
<generator class="native"/>
</id>
<property name="title"/>
<property name="year"/>
<set name="actors" inverse="true" cascade="save-update">
<key column="movieid"/>
<one-to-many class="MovieActor" />
</set>
</class>
</hibernate-mapping>
Where previously it never got as far as to starting my app, it now does. However, when running this test:
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();
Movie movie = (Movie)session.createQuery(
"from Movie where movieid=" + movieId)
.uniqueResult();
System.out.println("Movie: " + movie.getTitle());
Collection<Actor> actors = movie.getActors();
Iterator<Actor> actor = actors.iterator();
while (actor.hasNext()) {
Actor a = actor.next();
System.out.println("\t" + a.getName() + "(" + a.getSex() + ")");
}
session.getTransaction().commit();
I get the SQL below which errors as the columns 'movie' and 'actor' are not in the movies2actor table.
Hibernate:
select
movie0_.movieid as movieid0_,
movie0_.title as title0_,
movie0_.year as year0_
from
movies movie0_
where
movieid=1074158
Movie: Star Wars (1977)
Hibernate:
select
actors0_.movieid as movieid1_,
actors0_.actorid as actorid1_,
actors0_.movieid as movieid2_0_,
actors0_.actorid as actorid2_0_,
actors0_.movie as movie2_0_,
actors0_.actor as actor2_0_
from
movies2actors actors0_
where
actors0_.movieid=?
I am obviously getting confused as to what it should be doing - should I not be able to use the Iterator above to get the actors for the movie?