Hibernate – Association ternaire
Dans une relation @ManyToMany entre 2 entities, on a parfois besoin d’exploiter la table intermédiaire en tant que Entity à part entière en Java et ce afin d’y ajouter d’autres attributs
Exemple de mise en place

import javax.persistence.Column;
import javax.persistence.Embeddable;
import java.io.Serial;
import java.io.Serializable;
import java.util.Objects;
/**
* Classe annotée @Embeddable et représentant la clé composite @EmbeddedId
* pour l'entity MovieActor
*/
@Embeddable
public class MovieActorId implements Serializable {
@Serial
private static final long serialVersionUID = 8271797224862737084L;
@Column(name = "movie_id")
private Long movieId;
@Column(name = "actor_id")
private Long actorId;
public MovieActorId() {}
public MovieActorId(Long movieId, Long actorId) {
this.movieId = movieId;
this.actorId = actorId;
}
@Override
public boolean equals(Object o) { // equals() de la classe MovieActorId
if (this == o) return true;
if (!(o instanceof MovieActorId)) return false;
MovieActorId that = (MovieActorId) o;
return movieId.equals(that.movieId) && actorId.equals(that.actorId);
}
@Override
public int hashCode() {
return Objects.hash(movieId, actorId);
}
}
Langage du code : PHP (php)
import javax.persistence.*;
import java.util.Objects;
/**
* Classe intermédiaire reliant Movie et Actor
* Elle a comme clé primaire composite MovieActorId et annotée @EmbeddedId
*/
@Entity
@Table(name = "movie_actor")
public class MovieActor {
@EmbeddedId
private MovieActorId id; // Clé primaire composée et représentée par la classe MovieActorId
@ManyToOne(fetch = FetchType.LAZY)
@MapsId("movieId")
@JoinColumn(name = "movie_id") // Pour faciliter le repérage
private Movie movie;
@ManyToOne(fetch = FetchType.LAZY)
@MapsId("actorId")
@JoinColumn(name = "actor_id")
private Actor actor;
private String character;
protected MovieActor() {}
public MovieActor(Movie movie, Actor actor) {
this.movie = movie;
this.actor = actor;
this.id = new MovieActorId(movie.getId(), actor.getId()); // Création d'un MovieActorId
}
public MovieActorId getId() {
return id;
}
public Movie getMovie() {
return movie;
}
public void setMovie(Movie movie) {
this.movie = movie;
}
public Actor getActor() {
return actor;
}
public MovieActor setActor(Actor actor) {
this.actor = actor;
return this;
}
public String getCharacter() {
return character;
}
public MovieActor setCharacter(String character) {
this.character = character;
return this;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof MovieActor)) return false;
MovieActor that = (MovieActor) o;
//return movie.equals(that.movie) && actor.equals(that.actor);
return Objects.equals(movie, that.movie) && Objects.equals(actor, that.actor);
}
@Override
public int hashCode() {
return Objects.hash(movie, actor);
}
}
Langage du code : PHP (php)
import javax.persistence.*;
import java.util.*;
import java.util.stream.Collectors;
@Entity
public class Movie {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
// ...
/**
* Par défaut FetchType.LAZY pour @OneToMany et @ManyToMany
* Et FetchType.EAGER pour @OneToOne et @ManyToOne
*/
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "movie")
private List<MovieActor> moviesActors = new ArrayList<>();
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public List<MovieActor> getMovieActors() {
return moviesActors;
}
/**
* Ajouter un "movieActor" dans la liste des "moviesActors"
* et penser également à lier ce "movieActor" à la liste des "moviesActors" de l'Actor
* @param actor
* @param character
* @return Movie
*/
public void addActor(Actor actor, String character) {
MovieActor movieActor = new MovieActor(this, actor).setCharacter(character);
this.moviesActors.add(movieActor);
actor.getMoviesActors().add(movieActor);
}
public void updateActor(Actor actor, String character) {
moviesActors.stream().forEach(movieActor -> {
if(movieActor.getActor().equals(actor) && movieActor.getMovie().equals(this)) {
movieActor.setCharacter(character);
}
});
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Movie)) return false;
Movie other = (Movie) o;
return getId().equals(other.getId())
&& getName().equals(other.getName())
&& getDescription().equals(other.getDescription())
&& getCertification() == other.getCertification()
&& getReviews().equals(other.getReviews());
}
@Override
public int hashCode() {
return Objects.hash(getId(), getName(), getDescription(), getCertification(), getReviews());
}
}
Langage du code : PHP (php)
import javax.persistence.*;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@Entity
public class Actor {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
// ...
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "actor")
private List<MovieActor> moviesActors = new ArrayList<>();
public Long getId() {
return id;
}
public Actor setId(Long id) {
this.id = id;
return this;
}
public List<MovieActor> getMoviesActors() {
return moviesActors;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Actor)) return false;
Actor other = (Actor) o;
if(id == null && other.getId() == null) {
return Objects.equals(getName(), other.getName())
&& Objects.equals(getFirstname(), other.getFirstname())
&& Objects.equals(getBirthdate(), other.getBirthdate());
} else {
return id != null && id.equals(other.getId());
}
}
@Override
public int hashCode() {
return 82;
}
}
Langage du code : PHP (php)