【问题标题】:Who should be parent in spring JPA relationship谁应该是春季JPA关系中的父母
【发布时间】:2021-06-11 11:44:22
【问题描述】:

我有 3 张桌子 bookpublisherauthor。这里authorpublisher 可以引用book 中的相同记录,因此我决定将book 设为关系父级。

但是我还想这样做,如果删除了publisherA,则与publisherA 相关的所有book 记录也将被删除。 author 也是如此。

我尝试使用 cascade,但结果恰恰相反,如果我删除 book,它会删除任何与本书相关的 publisherauthor

这是我的表

create table publisher(
    `PUBLISHER_ID` int auto_increment,
    `PUBLISHER_NAME` varchar(150),
    `CONTACT_NO` varchar(10),
    `EMAIL` varchar(30),
    `ADDRESS_LINE_1` varchar(255),
    `ADDRESS_LINE_2` varchar(255),
    `CITY` varchar(50),
    `STATE` varchar(50),
    `PINCODE` varchar(6),
    primary key(PUBLISHER_ID)
    );
    
create table author_book(
    `AUTHOR_ID` INT,
    `BOOK_ID` INT
);

create table author(
    `AUTHOR_ID` int auto_increment,
    `FIRST_NAME` varchar(255),
    `LAST_NAME` varchar(255),
    `EMAIL` varchar(30),
    `CONTACT_NO` VARCHAR(10),
    primary key(AUTHOR_ID)
);
create table book(
    `BOOK_ID` int auto_increment,
    `TITLE` varchar(255),
    `SUBJECT` varchar(255),
    `PUBLISHED_YEAR` int,
    `ISBN` varchar(30),
    `QUANTITY` int,
    `SHELF_DETAILS` varchar(255),    
    `PUBLISHER_ID` int,
    `BOOK_COST` INT,
    primary key(BOOK_ID)
);

author实体

@Entity
@Table(name="author")
public class Authors {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="AUTHOR_ID")
    private int authorId;
    
    @Column(name="FIRST_NAME")
    private String firstName;
    
    @Column(name="LAST_NAME")
    private String lastName;
    
    @Column(name="EMAIL")
    private String email;
    
    @Column(name="CONTACT_NO")
    private String contactNo;
    
    @JsonIgnore
    @ManyToMany(fetch = FetchType.LAZY, mappedBy = "authors")
    private Set<Books> books = new HashSet<Books>();

    //getter setter
}

publisher实体

package com.sprint.proj.entity;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "publisher")
public class Publishers {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="PUBLISHER_ID")
    private int publisherId;
    
    @Column(name="PUBLISHER_NAME")
    private String publisherName;
    
    @Column(name="CONTACT_NO")
    private String contactNo;
    
    @Column(name="EMAIL")
    private String email;
    
    @Column(name="ADDRESS_LINE_1")
    private String address1;
    
    @Column(name="ADDRESS_LINE_2")
    private String address2;
    
    @Column(name="CITY")
    private String city;
    
    @Column(name="STATE")
    private String state;
    
    @Column(name="PINCODE")
    private int pincode;
// getter and setters
}

book实体

@Entity
@Table(name = "book")
public class Books implements Serializable{
    private static final long serialVersionUID = 1L;
    
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="BOOK_ID")
    private int bookId;
    
    @Column(name="TITLE")
    private String title;
    
    @Column(name="SUBJECT")
    private String subject;
    
    @Column(name="PUBLISHED_YEAR")
    private int publishedYear;
    
    @Column(name="ISBN")
    private String isbn;
    
    @Column(name="QUANTITY")
    private int quantity;
    
    @Column(name="SHELF_DETAILS")
    private String shelfDetails;
    
    @Column(name="BOOK_COST")
    private int bookCost;
    
    @JsonIgnore
    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(name = "author_book", 
            joinColumns = { @JoinColumn(name = "BOOK_ID") }, 
            inverseJoinColumns = { @JoinColumn(name = "AUTHOR_ID") })
    private Set<Authors> authors = new HashSet<Authors>();
    
    @JsonIgnore
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name="PUBLISHER_ID")
    private Publishers publisher;
// getter and setters
}

【问题讨论】:

  • 我会保留映射并手动删除。
  • 如果一本书有多个作者,而您只删除其中一个,该怎么办?

标签: java mysql spring jpa spring-data-jpa


【解决方案1】:

这可以通过适当的外键约束在 MySQL 级别完成,例如 book/publisher 关系:

alter table book
add constraint fk_book_publisher_id
  foreign key (PUBLISHER_ID)
  references publisher(PUBLISHER_ID)
  -- no action on update,
  -- unless you want to allow publisher's PK (PUBLISHER_ID) to be updated
  -- (but I guess not):
  on update no action
  -- when the referenced record is deleted
  -- (so the record from table publisher),
  -- delete the referencing records too
  -- (so the records from table book):
  on delete cascade;

虽然关于book/author 关系,您的模型似乎允许一本书有多个作者(并且一个作者多本书),因此中间有author_book 连接表。在这种情况下,不幸的是,FK 不允许从authorbook 的级联删除(他们会留下“无作者”的书籍)。这需要由应用程序完成(可能由 JPA 完成)。但是,如果一本书有多个作者,而您只删除其中一个,该怎么办?

【讨论】:

    【解决方案2】:
    @JsonIgnore
    @ManyToMany(fetch = FetchType.LAZY, mappedBy = "authors" , cascade = Cascade.ALL)
    private Set<Books> books = new HashSet<Books>();
    
    @JsonIgnore
    @ManyToMany(fetch = FetchType.LAZY) --> ignore cascade here so it will be none
    @JoinTable(name = "author_book", 
            joinColumns = { @JoinColumn(name = "BOOK_ID") }, 
            inverseJoinColumns = { @JoinColumn(name = "AUTHOR_ID") })
    private Set<Authors> authors = new HashSet<Authors>();
    

    实际上,您可以使用作者存储库以级联方式删除所有图书,但如果您使用图书存储库删除,则不会删除作者,因为它在@ManyToMany 关系中被忽略。在两种情况下,关系表的记录总是被删除。

    此外,您无需在数据库脚本中指定更新或删除操作。

    【讨论】:

      【解决方案3】:

      我想建议通过更新手动软删除。

      https://blog.staynoob.cn/post/2019/05/when-soft-delete-meets-unique-index/

      然后将 where 子句添加到实体中以仅从存储库中获取未删除的实体

      Handling soft-deletes with Spring JPA

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-08-27
        • 1970-01-01
        • 2018-11-25
        • 1970-01-01
        • 2021-05-30
        • 2020-09-02
        • 2012-03-05
        • 1970-01-01
        相关资源
        最近更新 更多