Como você configurar uma relação muitos-para-muitos com a junção da tabela usando JPA / EclipseLink
-
22-08-2019 - |
Pergunta
Eu tenho 2 tabelas:
Filmes: FilmeID
Usuários: userID
Estas tabelas têm um relacionamento muitos para muitos através da tabela de fila, com um atributo adicional, listOrder:
Fila: FilmeID, ID do usuário, listOrder
Eu estou tentando modelar isso usando EclipseLink, mas estou recebendo um erro "mapeamento incompattible". Aqui está uma amostra do meu código:
@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();
}
}
O objetivo da QueueItemPK é para que eu possa ter a primária composta chave de FilmeID e userID. Eu não estou absolutamente certo de que este é o caminho correto para fazê-lo.
Este é o erro: Exceção Descrição: Um mapeamento incompatível foi encontrado entre [Classe de filme] e [QueueItem classe]. Isso geralmente ocorre quando o cardinalidade de um mapeamento não corresponde com a cardinalidade do seu backpointer. Eu tenho o mesmo erro com a classe do usuário (os erros alternativo).
Quando eu tomar as anotações @ id fora das variáveis ??de cinema e de usuário em QueueItem e fazer alguma outra chave a chave primária, no entanto, ele compila com sem erros.
Todas as sugestões serão apreciadas.
Obrigado, B.J.
Solução
Em primeiro lugar, como sugerido por Mike Cornell, o EmbeddedId / Class é provavelmente a escolha mais fácil de usar. No entanto, para responder à sua pergunta e código corrigido:
@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;
}
}
Como você pode ver que é neccessary que eles têm o tipo de ID é que eles têm para corresponder. não muito bonito, mas de trabalho. E eu sugiro usar os genéricos para seus conjuntos; marcas ist mais fácil de ler e mais seguro para o código.