-->
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.  [ 2 posts ] 
Author Message
 Post subject: JPA @OneToMany, FK is a part of composite PK on Many side
PostPosted: Sun Aug 16, 2009 12:52 pm 
Newbie

Joined: Thu Jul 17, 2008 6:44 pm
Posts: 9
Hi, I am trying to map 3 tables, basically N:M where the join table has few columns to be mapped, so I need it to be 1:N and N:1 :

Code:
User <- 1:N -> Watches <- N:1 -> Topic


Here are the tables:

Code:
CREATE TABLE  test_user (
  id int(10) unsigned NOT NULL,
  mail varchar(45) NOT NULL,
  PRIMARY KEY (id)
)

CREATE TABLE  test_watches (
  id_user int(10) unsigned NOT NULL,
  id_topic int(10) unsigned NOT NULL,
  poznamka varchar(45) DEFAULT NULL,
  PRIMARY KEY (id_user,id_topic)
)

CREATE TABLE test_topic (
  id int(10) unsigned NOT NULL,
  name varchar(45) NOT NULL,
  PRIMARY KEY (id)
)


I have tried many approaches, but always got some Exception.

The Watches entity uses @EmbeddedId: (I've also tried @IdClass.)

Code:
@Entity
@Table( name = "test_watches" )
public class TestWatching implements Serializable
{
  @EmbeddedId
  protected TestWatchingPK testWatchingPK;
 
  @Column( name = "poznamka" )
  private String poznamka;

  public TestWatching() { }
  public TestWatching( TestWatchingPK testWatchingPK ) { this.testWatchingPK = testWatchingPK; }
  public TestWatching( TestUser user, TestTopic topic ) {
    this.testWatchingPK = new TestWatchingPK( user.getId(), topic.getId() );
  }

  // ... and getters, setters & overrides.
}


Code:
@Embeddable
public class TestWatchingPK implements Serializable
{
  @Basic( optional = false )
  @Column( name = "id_user" )
  private int idUser;
 
  @Basic( optional = false )
  @Column( name = "id_topic" )
  private int idTopic;

  public TestWatchingPK() { }
  public TestWatchingPK( int idUser, int idTopic ) {
    this.idUser = idUser;
    this.idTopic = idTopic;
  }

  // ... and getters, setters & overrides.
}


Then there's the User entity:

Code:
@Entity  @Table( name = "test_user" )
public class TestUser implements Serializable
{
  ...
  @OneToMany
  @JoinTable(name="test_watches")
  public Set<TestWatching> topicWatches = new HashSet();
  ...
}


This is the first relation I am trying to map and can't get over it. The above simple mapping says:

Code:
org.hibernate.AnnotationException: referencedColumnNames(id_user) of cz.dynawest.isir.entities.TestUser.topicWatches referencing cz.dynawest.isir.entities.TestWatching not mapped to a single property


I have also tried to play with @JoinColumn, with no success:

Code:
  @OneToMany(/*mappedBy="idUser"*/)
  @JoinTable(name="test_watches",
    joinColumns={   @JoinColumn(name="id_user", referencedColumnName="id")  }
  )
  public Set<TestWatching> topicWatches = new HashSet();


I've found a solution of similar problem, which uses XML mapping, viewtopic.php?f=1&t=998512
But when I use @JoinColumn with either name or referencedColumnName, Hibernate uses "" as a column name.

Perhaps adding an ID column to the test_watches table and converting the composite PK to an unique constraint could help, but changing the structure of the DB is the last option for me.

So please, is there any example of mapping one-to-many relation ship with FK being part of composite PK on the Many side? Is it possible at all?



I also had a look at Hibernate test-suite, https://anonsvn.jboss.org/repos/hiberna ... tions/cid/ , but no such case there.

I use JPA annotations, but I am ok with any Hibernate-specific.



Thanks a lot,
Ondra


Top
 Profile  
 
 Post subject: Re: JPA @OneToMany, FK is a part of composite PK on Many side
PostPosted: Mon Aug 17, 2009 5:49 am 
Newbie

Joined: Thu Jul 17, 2008 6:44 pm
Posts: 9
In the end, I have found one configuration of the whole N:M thing which hibernate doesn't spit out.

Code:
@Entity
@Table( name="poh_users_watch_topics" )
@IdClass(value=UserTopicWatchingPK.class)
public class UserTopicWatching implements Serializable, Comparable<UserTopicWatching> {
  @Id
  private User id_user;
  public User getUser() {    return id_user;  }

  @Id
  private Topic id_topic;
  public Topic getTopic() {    return id_topic;  }
}


Code:
@Embeddable
public class UserTopicWatchingPK implements Serializable {

  private User id_user;
  private Topic id_topic;

  @ManyToOne
  @JoinColumn(name="id_user")
  public User getUser() {         return id_user;      }
 
  @ManyToOne
  @JoinColumn(name="id_topic")
  public Topic getTopic() {         return id_topic;      }
  ...
}


Code:
  @OneToMany(cascade=CascadeType.ALL , mappedBy="id_topic")
  Set<UserTopicWatching> watchingUsers = new HashSet<UserTopicWatching>();


Code:
  @OneToMany(cascade=CascadeType.ALL, mappedBy="id_user")
  Set<UserTopicWatching> topicWatchings = new HashSet<UserTopicWatching>();


The only thing I wasn't able to do is to force Hibernate to use
Code:
@Id private User id_user;

instead of
Code:
@Id private User user;

In the latter case, Hibernate uses "user" as the column name.
How do I override this?

Thanks


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