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)