How do you Set Up a Many-to-Many Relationship with Junction Table using JPA/EclipseLink

StackOverflow https://stackoverflow.com/questions/878374

  •  22-08-2019
  •  | 
  •  

Question

I have 2 tables:

Movies: movieID

Users: userID

These tables have a many to many relationship through the Queue table, with an additional attribute, listOrder:

Queue: movieID, userID, listOrder

I'm attempting to model this using EclipseLink, but am getting an "incompattible mapping" error. Here is a sampling of my code:


@Entity
@Table(name="movieinventory")
public class Movie implements Serializable
{
       private static final long serialVersionUID = 1L;

       @Id
       @GeneratedValue
       private Integer movieID;

       @OneToMany(mappedBy="movie")
       private Set moviesInQueue;

       ...Getters/Setters...
}

@Entity
@Table(name="Users")
public class User implements Serializable
{
       private static final long serialVersionUID = 1L;

       @Id
       @GeneratedValue
       private Integer userID;

       @OneToMany(mappedBy="user")
       private Set moviesInQueue;

      ...Getters/Setters...
}

@IdClass(QueueItemPK.class)
@Entity
@Table(name="queue")
public class QueueItem
{
       @Id
       @ManyToOne
       @JoinColumn(name="movieID")
       private Movie movie;

       @Id
       @ManyToOne
       @JoinColumn(name="userID")
       private User user;

       @Basic
       private String listOrder;

       ...Getters/Setters...
}

public class QueueItemPK implements Serializable
{
       private static final long serialVersionUID = 1L;

       private Movie movie;
       private User user;

       ...Getters/Setter...

       public int hashCode()
       {
           return (movie.getMovieID() + "|" + user.getUserID()).hashCode();
       }

       public boolean equals(Object obj)
       {
           if (obj == this) return true;
           if (obj == null) return false;
           if (!(obj instanceof QueueItemPK)) return false;
           QueueItemPK pk = (QueueItemPK) obj;
           return pk.movie.getMovieID() == movie.getMovieID() 
               && pk.user.getUserID() == user.getUserID();
       }
}

The purpose of the QueueItemPK is so that I can have the composite primary key of movieID and userID. I'm not absolutely sure this is the correct way to do it.

This is the error: Exception Description: An incompatible mapping has been encountered between [class Movie] and [class QueueItem]. This usually occurs when the cardinality of a mapping does not correspond with the cardinality of its backpointer. I have the same error with the User class (the errors alternate).

When I take the @Id annotations off of the movie and user variables in QueueItem and make some other key the primary key, however, it compiles with no errors.

Any suggestions would be appreciated.

Thanks, B.J.

Was it helpful?

Solution

First of all, as suggested by Mike Cornell, the EmbeddedId/Class is probably the easier-to-use choice. Nonetheless, to answer to your question and corrected code:

@IdClass(QueueItemPK.class)
@Entity
@Table(name="queue")
public class QueueItem
{
       @Id
       @ManyToOne(optional=false)
       @PrimaryKeyJoinColumn(name="movieID")
       private Movie movie;

       @Id
       @ManyToOne(optional=false)
       @PrimaryKeyJoinColumn(name="userID")
       private User user;

       @Basic
       private String listOrder;

       ...Getters/Setters...
}

public class QueueItemPK implements Serializable
{
       private static final long serialVersionUID = 1L;

       @Id
       @Column(name="movieID")
       private Integer movie;
       @Id
       @Column(name="userID")
       private Integer user;

       ...Getters/Setter...

       public int hashCode()
       {
           return (movie.getMovieID() + "|" + user.getUserID()).hashCode();
       }

       public boolean equals(Object obj)
       {
           if (obj == this) return true;
           if (obj == null) return false;
           if (!(obj instanceof QueueItemPK)) return false;
           QueueItemPK pk = (QueueItemPK) obj;
           return pk.movie == movie 
               && pk.user == user;
       }
}

As you can see it is neccessary that they have the type of the id's they've to match. not very beautiful, but working. And i suggest using generics for your Sets; makes ist easier to read and more secure to code.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top