简体   繁体   English

如何插入具有多对多关系的实体?

[英]How to insert entity with many to many relation?

I'm working with Spring framework.我正在使用 Spring 框架。 I have two entities, Movie and Actor, so a Movie can have many actors and an Actor can play in many Movie.我有两个实体,电影和演员,所以电影可以有很多演员,演员可以在很多电影中播放。 Following we have the classes:以下是我们的课程:

import java.util.List;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;

@Entity
public class Actor {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private String surname;
    private String age;

    @ManyToMany
    @JoinTable(name = "movie_actor")
    private List<Movie> movies;

    public Actor(String name, String surname, String age) {
        this.name = name;
        this.surname = surname;
        this.age = age;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSurname() {
        return surname;
    }

    public void setSurname(String surname) {
        this.surname = surname;
    }

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }

    public List<Movie> getMovies() {
        return movies;
    }

    public void setMovies(List<Movie> movies) {
        this.movies = movies;
    }   
}
import java.util.List;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;

@Entity
public class Movie {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String title;
    private String genre;
    private String year;

    @ManyToMany(mappedBy = "movies")
    private List<Actor> actors;

    public Movie(String title, String genre, String year, List<Actor> actors) {
        this.title = title;
        this.genre = genre;
        this.year = year;
        this.actors = actors;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getGenre() {
        return genre;
    }

    public void setGenre(String genre) {
        this.genre = genre;
    }

    public String getYear() {
        return year;
    }

    public void setYear(String year) {
        this.year = year;
    }

    public List<Actor> getActors() {
        return actors;
    }

    public void setActors(List<Actor> actors) {
        this.actors = actors;
    }
}

I have used @ManyToMany annotations to define the relation between them.我使用@ManyToMany 注释来定义它们之间的关系。

At this point, I have in H2 a table Actor that has ID, AGE, NAME and SURNAME columns, table Movie that has ID, GENRE, TITLE and YEAR, and a new table MOVIE_ACTOR because of the annotation with ACTORS_ID and MOVIES_ID columns.此时,我在 H2 中有一个具有 ID、AGE、NAME 和 SURNAME 列的表 Actor,具有 ID、GENRE、TITLE 和 YEAR 的表 Movie,以及一个新表 MOVIE_ACTOR,因为注释带有 ACTORS_ID 和 MOVIES_ID 列。 Until here it seems okey.直到这里看起来还不错。

Now, if I save a movie (I have implemented the service and repository extending jpaRepository for both entities):现在,如果我保存一部电影(我已经为两个实体实现了扩展 jpaRepository 的服务和存储库):

@GetMapping("/create")
public void create() {
        Actor actor1 = new Actor("Pedro", "Perez", "40");
        Actor actor2 = new Actor("Alfredo", "Mora", "25");
        Actor actor3 = new Actor("Juan", "Martinez", "20");
        Actor actor4 = new Actor("Mario", "Arenas", "30");

        List<Actor> actorList = new ArrayList<>();
        actorList.add(actor1);
        actorList.add(actor2);
        actorList.add(actor3);
        actorList.add(actor4);

        Movie movie = new Movie("Titanic", "Drama", "1984", actorList);

        movieService.create(movie);
    }

(I know that it is not a get request, but just for check if a movie is correctly saved just accessing to the endpoint) What I obtain is that in the table Movie the 4 columns are added correctly, but neither ACTOR and MOVIE_ACTOR are completed so actorList is ommited, this two tables are empty. (我知道这不是一个获取请求,而只是为了检查是否正确保存了仅访问端点的电影)我得到的是在表 Movie 中正确添加了 4 列,但 ACTOR 和 MOVIE_ACTOR 都没有完成所以actorList被省略了,这两个表是空的。 Why this happens and how can I solved it?为什么会发生这种情况,我该如何解决?

Thank you so much for your help!非常感谢你的帮助!

Maybe you implemented something like this in your service methods (you did not show it) but I would assume that it is missing: You do not cascade anything (respectively save objects of the other class).也许你在你的服务方法中实现了类似的东西(你没有展示它),但我认为它丢失了:你没有级联任何东西(分别保存另一个类的对象)。 You should change your @ManyToMany annotation to @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}) .您应该将@ManyToMany注释更改为@ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}) This leads to cascading the merge and persist operation (saving a new object or any changes leads to automatically updating the other one).这会导致级联合并和持久化操作(保存新的 object 或任何更改都会导致自动更新另一个)。

Also consider adding proper add and remove methods for your lists like described in this article and good equals and hashCode methods .还可以考虑为您的列表添加适当的添加和删除方法,如本文所述,以及良好的equals 和 hashCode 方法

In general, you could find very good descriptions of Hibernate related issues on the page of Vlad Mihalcea .一般来说,您可以在Vlad Mihalcea的页面上找到有关 Hibernate 相关问题的非常好的描述。

Update: Implementation Based on Post of @Alan Hay更新:基于@Alan Hay 的帖子实施

Model Model

@Entity
public class Actor {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private String surname;
    private String age;

    @ManyToMany
    @JoinTable(name = "movie_actor")
    private List<Movie> movies = new ArrayList<>();

    public void addMovie(Movie movie) {
        movies.add(movie);
        movie.getActors().add(this);
    }

    public void removeMovie(Movie movie) {
        movies.remove(movie);
        movie.getActors().remove(this);
    }

    // Constructors, getters and setters...

    // Equals and hashCode methods a la 
    // https://vladmihalcea.com/how-to-implement-equals-and-hashcode-using-the-jpa-entity-identifier/
}
@Entity
public class Movie {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String title;
    private String genre;
    private String year;

    @ManyToMany(mappedBy = "movies", cascade = {CascadeType.PERSIST, CascadeType.MERGE})
    private List<Actor> actors;

    public Movie(String title, String genre, String year, List<Actor> actors) {
        this.title = title;
        this.genre = genre;
        this.year = year;
        actors.forEach(a -> a.addMovie(this));
    }

    // Getters and setters...
}

Create Method创建方法

@GetMapping("/create")
public void create() {
    Actor actor1 = new Actor("Pedro", "Perez", "40");
    Actor actor2 = new Actor("Alfredo", "Mora", "25");
    Actor actor3 = new Actor("Juan", "Martinez", "20");
    Actor actor4 = new Actor("Mario", "Arenas", "30");

    List<Actor> actorList = new ArrayList<>();
    actorList.add(actor1);
    actorList.add(actor2);
    actorList.add(actor3);
    actorList.add(actor4);

    Movie movie = new Movie("Titanic", "Drama", "1984", actorList);

    movieService.create(movie);
}

There are 2 issues here.这里有2个问题。

Firstly, you have not set the cascade options on the relationship.首先,您没有在关系上设置级联选项。

@ManyToMany(mappedBy = "movies", cascade = {CascadeType.PERSIST, CascadeType.MERGE})
private List<Actor> actors;

Secondly, in the case of a bi-directional relationship it is your responsibility to maintain both sides of the relationship in the in-memory model.其次,在双向关系的情况下,您有责任在内存 model 中维护关系的双方。 The relationship here is being managed by Actor (the side without mappedBy ) but you have not added any movies to the movies collection in Actor.此处的关系由 Actor(没有mappedBy的一侧)管理,但您尚未将任何电影添加到 Actor 中的电影集合中。

So, if you iterate actors in your movies constructor and add the movie a.getMovies().add(this) then both sides will be set and the data should be saved as requested.因此,如果您在电影构造函数中迭代演员并添加电影a.getMovies().add(this)则双方都将被设置并且数据应按要求保存。

The Hibernate docs suggest @ManyToMany mappings should be avoided as in most cases you are likely to want to store additional data related to the association: in your case for example, character name. Hibernate 文档建议应避免使用@ManyToMany映射,因为在大多数情况下,您可能希望存储与关联相关的其他数据:例如,字符名称。 A more flexible option is then to create a Join Entity, say, MovieAppearance which has Movie, Actor, and other properties as required.一个更灵活的选择是创建一个加入实体,例如,MovieAppearance,它具有电影、演员和其他所需的属性。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何删除具有多对多关系的实体? JPA - How to delete entity with many to many relation? JPA 如何使用MockMvc更新多对多关系的实体? - How to update entity with many to many relation using MockMvc? 单个实体的多对多关系-Hibernate - Many-to-many relation of a single entity - Hibernate Android Room:插入具有 ViewModel、Repository、Database 的多对多关系实体 - Android Room: Insert a many-to-many relation entity with ViewModel, Repository, Database JPA:如何具有相同实体类型的一对多关系 - JPA: How to have one-to-many relation of the same Entity type Spring Boot JPA:如何删除多对一关系的子实体 - Spring Boot JPA : How to delete child entity of a Many to One relation 对于与数据实体具有多对一关系的 JPA 实体,如何根据数据实体的方法调用结果对对象列表进行排序? - For a JPA entity with many to 1 relation to a data entity, how to sort a list of objects by the result of a method call of the data entity? 具有两个多对一关系的实体关系 - Entity relation with two many to one relations 如何在多对多关系中使用Hibernate在连接表中插入常量值? - How to insert constant value in a join table with Hibernate in a many-to-many relation? 如何只删除多对多关系中的关系? - How to delete only the relation in a many to many relationship?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM