JPA中@OneToOne、@OneToMany、@ManyToMany的映射關系


@OneToOne

單向關系

假設學生和學生卡是一對一關系,那么:

學生類:

import lombok.Data;

import javax.persistence.*;
import java.io.Serializable;

@Entity
@Data
@Table(name = "student")
public class Student implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false)
    private String name;

    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "card_id")
    private Card card;
}

學生卡類:

import lombok.Data;

import javax.persistence.*;
import java.io.Serializable;

@Entity
@Table(name = "card")
@Data
public class Card implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false)
    private Integer number;
}

生成的數據庫表如下:

  • @OneToOne和@JoinColumn定義了關系維護端
  • 關系維護端(Student)生成的數據庫表包含外鍵,關系被維護端(Card)生成的數據庫表不包含外鍵
  • 當保存關系維護端(Student)前,會先保存關系被維護端(Card),同時更新外鍵值;
  • 如果設置了級聯刪除,當刪除關系維護端(Student)時,關系被維護端(Card)將一塊被刪除;否則只刪除關系維護端(Student)自己
  • 單向關系只保證關系維護端(Student)的每個實例有且只有一個Card實例,但無法保證一個關系被維護端(Card)的實例只被一個關系維護端(Student)的實例引用即一張學生卡可能對應多個人
  • 當刪除關系被維護端(Card)時,程序報錯Cannot delete or update a parent row: a foreign key constraint fails,是由於被維護端的數據被通過外鍵引用無法刪除

雙向

如果更改為雙向關系,只需改動關系被維護端:

import lombok.Data;

import javax.persistence.*;
import java.io.Serializable;

@Entity
@Table(name = "card")
@Data
public class Card implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false)
    private Integer number;
    
    @OneToOne(mappedBy = "card")
    private Student student;
}
  • @OneToOne的mappedBy屬性定義了關系被維護端,表示主動讓出放棄維護權,由當前被標注字段所屬類型(Student類)的類屬性名(card屬性名)負責維護關系,類屬性名是當前類的實例或實例集合
  • 關系維護端(Student)生成的數據庫表包含外鍵,關系被維護端(Card)生成的數據庫表不包含外鍵
  • 當保存關系維護端(Student)前,會先保存關系被維護端(Card),同時更新外鍵值;如果通過關系被維護端來保存關系維護端實例,關系維護端實例會保存,但外鍵值為空或不更新
  • 雙向關系保證關系維護端(Student)的每個實例有且只有一個Card實例,同時保證關系被維護端(Card)的實例只被一個關系維護端(Student)的實例引用

@OneToMany

單向

假設一個學校有多個教師,那么:

學校類:

import lombok.Data;

import javax.persistence.*;
import java.io.Serializable;
import java.util.List;

@Entity
@Table(name = "school")
@Data
public class School implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false)
    private String name;

    @OneToMany(cascade = CascadeType.ALL)
    @JoinColumn(name = "schoolIDid")
    private List<Teacher> teacherList;
}

教師類:

import lombok.Data;

import javax.persistence.*;
import java.io.Serializable;
import java.util.List;

@Entity
@Table(name = "teacher")
@Data
public class Teacher implements Serializable{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false)
    private String name;

    @ManyToOne
    @JoinColumn(name = "schoolIDid")
    private School school;
}

生成的數據庫表如下:

在一對多關系中,多的一方是關系維護端即@ManyToOne定義關系維護端,@OneToMany定義關系被維護端

關系維護端生成的數據庫表包含外鍵,關系被維護端生成的數據表不包含外鍵。

關系維護端負責外鍵記錄的更新,關系被維護端沒有權利更新外鍵字段

@JoinColumn作用:

  • 阻止生成中間表。如果想阻止生成中間表,關系被維護端(一的一方)必須標注@JoinColumn
  • 指定外鍵名。默認外鍵名為關系被維護端的表名加下划線加id,如果指定外鍵名則關系維護端和關系被維護端都必須標注@JoinColumn

如果關系被維護端沒有使用@JoinColumn,那么數據庫會生成中間表:

不同於一對一關系,關系維護端保存前必須先維護關系被維護端,否則報錯

雙向

只須在關系被維護端的@OneToMany注解中添加mappedBy屬性

@MonyToMony

單向

一對多和一對一關系,可以用外鍵實現;多對多關系只能通過中間表進行映射。

假設一個學生有多個老師,一個老師有多個學生,那么:

關系維護端注解如下:

@ManyToMany (cascade = CascadeType.REFRESH)
 
@JoinTable (//關聯表
 
name = "student_teacher" , //關聯表名
 
inverseJoinColumns = @JoinColumn (name = "teacher_id" ),//被維護端外鍵
 
joinColumns = @JoinColumn (name = "student_id" )       //維護端外鍵
)
private Set<Teacher> teachers;

關系被維護端注解如下:

@ManyToMany (fetch = FetchType.LAZY)
 
@JoinTable (//關聯表
 
name = "student_teacher" , //關聯表名
 
inverseJoinColumns = @JoinColumn (name = "student_id" ),//被維護端外鍵
 
joinColumns = @JoinColumn (name = "teacher_id" )       //維護端外鍵
)
private Set<Student> students;
  • 關系維護端刪除時,如果中間表存在些紀錄的關聯信息,則會刪除該關聯信息
  • 關系被維護端刪除時,如果中間表存在些紀錄的關聯信息,則會刪除失敗

關聯表名 = 主表表名+_下划線+從表表名

joinColumns屬性=當前實體類數據庫表名+_下划線+id

雙向

關系維護端注解不變,關系被維護端注解更改為:

@ManyToMany (fetch = FetchType.LAZY, 
             mappedBy = "teachers",         //通過維護端的屬性關聯
             cascade = CascadeType.REFRESH
)
private Set<Student> students;


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM