Java 如何从JPA中的联接表中删除数据

Java 如何从JPA中的联接表中删除数据,java,mysql,spring-boot,hibernate,jpa,Java,Mysql,Spring Boot,Hibernate,Jpa,我试图创建一个图书馆管理系统,因为我创建了两个实体Student和Books都是使用@manytomy关系连接的,所以我使用了另一个联接表,当学生从图书馆发行图书时,但当学生返回包含联接表中两个ID的行的图书,但当我尝试删除联接表中的所有数据或删除我的学生和图书时 这是我的代码,请告诉我我做错了什么,最好的做法是什么 学生实体 package com.Library.LibraryManagement.Entity; import java.sql.Timestamp; import java

我试图创建一个图书馆管理系统,因为我创建了两个实体
Student
Books
都是使用
@manytomy
关系连接的,所以我使用了另一个联接表,当学生从图书馆发行图书时,但当学生返回包含联接表中两个ID的行的图书,但当我尝试删除联接表中的所有数据或删除我的学生和图书时 这是我的代码,请告诉我我做错了什么,最好的做法是什么

学生实体

package com.Library.LibraryManagement.Entity;

import java.sql.Timestamp;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;

@Entity
@Table(name="student")
public class Student {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="id")
    private Integer id;
    @Column(name="first_name")
    private String firstName;
    @Column(name="last_name")
    private String lastName;
    @Column(name="student_email")
    private String email;
    @Column(name="student_course")
    private Integer course;
    @Column(name="date_of_birth")
    private String dateOfBirth;
    @Column(name="student_status")
    private Integer status;
    @Column(name="added_at")
    private Timestamp addedAt;
    
    @ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinTable(name="student_books",
                joinColumns=@JoinColumn(name = "student_id"),
                inverseJoinColumns = @JoinColumn(name="books_id"))
    private List<Books> books;
    
    
    public Student() {
    //Empty Constructor 
    }

    public Student(String firstName, String lastName, String email, Integer course,String dateOfBirth,Integer status,Timestamp addedAt) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.email = email;
        this.course = course;
        this.dateOfBirth = dateOfBirth;
        this.status = status;
        this.addedAt = addedAt;
    }

    
    public Integer getId() {
        return id;
    }

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

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public Integer getCourse() {
        return course;
    }

    public void setCourse(Integer course) {
        this.course = course;
    }

    public String getDateOfBirth() {
        return dateOfBirth;
    }

    public void setDateOfBirth(String dateOfBirth) {
        this.dateOfBirth = dateOfBirth;
    }
    
    public Integer getStatus() {
        return status;
    }

    public void setStatus(Integer status) {
        this.status = status;
    }

    public Timestamp getAddedAt() {
        return addedAt;
    }

    public void setAddedAt(Timestamp addedAt) {
        this.addedAt = addedAt;
    }

    public List<Books> getBooks() {
        return books;
    }

    public void setBooks(List<Books> books) {
        this.books = books;
    }
    
    public void removeBook(Books boo) {
        this.books.remove(boo);
        boo.getStudents().remove(this);
    }

    

    @Override
    public String toString() {
        return "{\"id\":\"" + id + "\", \"firstName\":\"" + firstName + "\", \"lastName\":\"" + lastName
                + "\", \"email\":\"" + email + "\", \"course\":\"" + course + "\", \"dateOfBirth\":\"" + dateOfBirth
                + "\", \"status\":\"" + status + "\", \"addedAt\":\"" + addedAt + "\"}";
    }

}
package com.Library.LibraryManagement.Entity;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;

@Entity
@Table(name="books")
public class Books {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="id")
    private Integer id;
    @Column(name="book_name")
    private String bookName;
    @Column(name="book_publisher")
    private String bookPublisherName;
    @Column(name="book_description")
    private String bookDescription;
    @Column(name="book_language")
    private String bookLanguage;
    @Column(name="book_in_stock")
    private Integer bookInStock;
    @Column(name="added_at")
    private Timestamp addedAt;
    @Column(name="deleted")
    private Integer deleted;

    @ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinTable(name="student_books",
                joinColumns=@JoinColumn(name = "books_id"),
                inverseJoinColumns = @JoinColumn(name="student_id"))
    private List<Student> students;
    
    public Books() {
        
    }
    
    public Books(String bookName, String bookPublisherName, String bookDescription, String bookLanguage,Timestamp addedAt,
            Integer bookInStock,Integer deleted) {
        this.bookName = bookName;
        this.bookPublisherName = bookPublisherName;
        this.bookDescription = bookDescription;
        this.bookLanguage = bookLanguage;
        this.bookInStock = bookInStock;
        this.addedAt =addedAt;
        this.deleted = deleted;
    }

    public Integer getId() {
        return id;
    }

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

    public String getBookName() {
        return bookName;
    }

    public void setBookName(String bookName) {
        this.bookName = bookName;
    }

    public String getBookPublisherName() {
        return bookPublisherName;
    }

    public void setBookPublisherName(String bookPublisherName) {
        this.bookPublisherName = bookPublisherName;
    }

    public String getBookDescription() {
        return bookDescription;
    }

    public void setBookDescription(String bookDescription) {
        this.bookDescription = bookDescription;
    }

    public String getBookLanguage() {
        return bookLanguage;
    }

    public void setBookLanguage(String bookLanguage) {
        this.bookLanguage = bookLanguage;
    }

    public Integer getBookInStock() {
        return bookInStock;
    }

    public void setBookInStock(Integer bookInStock) {
        this.bookInStock = bookInStock;
    }
    
    public Timestamp getAddedAt() {
        return addedAt;
    }

    public void setAddedAt(Timestamp addedAt) {
        this.addedAt = addedAt;
    }

    public Integer getDeleted() {
        return deleted;
    }

    public void setDeleted(Integer deleted) {
        this.deleted = deleted;
    }
    
    public List<Student> getStudents() {
        return students;
    }

    public void setStudents(List<Student> students) {
        this.students = students;
    }
    
    
    public void removeBook(Student stu) {
        this.students.remove(stu);
        stu.getBooks().remove(this);
    }
    

    @Override
    public String toString() {
        return "{\"id\":\"" + id + "\", \"bookName\":\"" + bookName + "\", \"bookPublisherName\":\"" + bookPublisherName
                + "\", \"bookDescription\":\"" + bookDescription + "\", \"bookLanguage\":\"" + bookLanguage
                + "\", \"bookInStock\":\"" + bookInStock + "\", \"addedAt\":\"" + addedAt + "\", \"deleted\":\""
                + deleted + "\"}";
    }
    
    //Convience MEthods to help with adding the student
    public void addStudent(Student theStudent) {
        if(students ==null) {
            students = new ArrayList<>();
        }
        students.add(theStudent);
    }
}
应该是

student.getBooks().remove(book);

entityManger.save(student)
应该是

student.getBooks().remove(book);

entityManger.save(student)

这是因为您正在使用
entityManager.remove
。由于级联,该命令将删除一个学生以及与之关联的所有书籍

如果您只想从关联中删除一本书,那么
returnBook
方法应该如下所示:

@Transactional
public void returnBook(Student student, Books book) {
    try {
         if(student !=null && book !=null) {
             Student entityStudent = entityManager.getReference( Student.class, student.getId())
             Book entityBook = entityManager.getReference( Book.class, book.getId())
             entityStudent.removeBook(entityBook);
        }
    }
...
}
在提交或刷新会话期间,更改将传播到数据库

注意,我添加了
getReference()
调用,因为我不知道
student
book
是否为托管实体。如果是,则无需使用
getReference()

假设这就是
removeBook
的样子:

    public void removeBook(Book book) {
        this.books.remove( book );
        book.getStudents().remove( this );
    }
如上所述,重要的是更新关联的双方

此外,其中一个实体上的关联映射应为:

@ManyToMany(mappedBy = "...")
您应该决定哪个实体拥有该关联


顺便问一下,您确定您试图实现的映射不是Hibernate ORM文档中描述的映射,如示例172所示。具有链接实体的双向多对多?

这是因为您使用的是
entityManager。请删除
。由于级联,该命令将删除一个学生以及与之关联的所有书籍

如果您只想从关联中删除一本书,那么
returnBook
方法应该如下所示:

@Transactional
public void returnBook(Student student, Books book) {
    try {
         if(student !=null && book !=null) {
             Student entityStudent = entityManager.getReference( Student.class, student.getId())
             Book entityBook = entityManager.getReference( Book.class, book.getId())
             entityStudent.removeBook(entityBook);
        }
    }
...
}
在提交或刷新会话期间,更改将传播到数据库

注意,我添加了
getReference()
调用,因为我不知道
student
book
是否为托管实体。如果是,则无需使用
getReference()

假设这就是
removeBook
的样子:

    public void removeBook(Book book) {
        this.books.remove( book );
        book.getStudents().remove( this );
    }
如上所述,重要的是更新关联的双方

此外,其中一个实体上的关联映射应为:

@ManyToMany(mappedBy = "...")
您应该决定哪个实体拥有该关联


顺便问一下,您确定您试图实现的映射不是Hibernate ORM文档中描述的映射,如示例172所示。具有链接实体的双向多对多

您的多对多关系映射不正确

他说:

每一个多对多协会都有两个方面,一个是所有者,一个是所有者 非拥有方,或相反方在上指定联接表 拥有方。如果关联是双向的,则任何一方都可以是双向的 指定为拥有方如果关系是双向的, 非拥有方必须使用
多个
注释以指定所属对象的关系字段或属性 一边

(重点补充)

您的注释映射关系就像双方都拥有它一样,这是不正确的


选择拥有方后,可以通过更新拥有方上的“关系”字段并保存修改后的拥有实体来修改关系。你有其他的答案说明如何做到这一点。您可能还希望对非拥有方进行相应的更改,或者刷新非拥有方实体以使该方的关系字段同步。

您的多对多关系映射不正确

他说:

每一个多对多协会都有两个方面,一个是所有者,一个是所有者 非拥有方,或相反方在上指定联接表 拥有方。如果关联是双向的,则任何一方都可以是双向的 指定为拥有方如果关系是双向的, 非拥有方必须使用
多个
注释以指定所属对象的关系字段或属性 一边

(重点补充)

您的注释映射关系就像双方都拥有它一样,这是不正确的


选择拥有方后,可以通过更新拥有方上的“关系”字段并保存修改后的拥有实体来修改关系。你有其他的答案说明如何做到这一点。您可能还希望对非拥有方进行相应的更改,或刷新非拥有方实体以使该方的关系字段同步。

不要使用returnBooke方法,请使用以下方法:

 @Override
    @Transactional
    public void returnBok(Student student, Books book) {
        try {
            if (student != null && book != null) {
                student.getBooks().removeIf(books -> {
                    return Objects.equals(book.getId(), books.getId());
                });
                entityManager.save(student);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

因为在上述方法中,您正在删除整个student对象
entityManage.remove(student),这就是您的学生被删除并到期的原因
cascade=CascadeType。映射书对象中的所有
也将被删除

还有一个建议。而不是填充Getter、Setter和构造函数

使用Lombok插件:


不要使用您的返回方法,请使用以下方法:

 @Override
    @Transactional
    public void returnBok(Student student, Books book) {
        try {
            if (student != null && book != null) {
                student.getBooks().removeIf(books -> {
                    return Objects.equals(book.getId(), books.getId());
                });
                entityManager.save(student);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

因为在上述方法中,您正在删除整个student对象
entityManage.remove(student),这就是您的学生被删除并到期的原因
cascade=CascadeType。映射书对象中的所有
也将被删除

还有一个建议。而不是填充Getter、Setter和构造函数

使用Lombok插件:

这是否回答了您的问题