自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Jpa 中怎么玩一對(duì)多?

開(kāi)發(fā) 前端
Jpa 中的一對(duì)一、一對(duì)多沒(méi)搞明白的話,總會(huì)覺(jué)得有點(diǎn)繞,今天咱們來(lái)簡(jiǎn)單聊聊這個(gè)話題。

Jpa 中的一對(duì)一、一對(duì)多沒(méi)搞明白的話,總會(huì)覺(jué)得有點(diǎn)繞,今天咱們來(lái)簡(jiǎn)單聊聊這個(gè)話題。

1. 一對(duì)一

比如說(shuō)一個(gè)學(xué)校有一個(gè)地址,一個(gè)地址只有一個(gè)學(xué)校。

那么我們可以按照如下方式來(lái)設(shè)計(jì)類:

@Data
@Entity
@Table(name = "t_address")
public class Address {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer aid;
private String province;
private String city;
private String area;
private String phone;
@OneToOne(cascade = CascadeType.ALL)
private School school;
}
@Data
@Entity
@Table(name = "t_school")
public class School {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer sid;
private String name;
@OneToOne(cascade = CascadeType.ALL)
private Address address;
}

一對(duì)一的關(guān)系,可以只在 School 中維護(hù),也可以只在 Address 中維護(hù),也可以兩者都維護(hù),具體哪種,那就看需求了。

在上面的例子中,我們?cè)?School 和 Address 中都通過(guò) @OneToOne 注解來(lái)維護(hù)了一對(duì)一的關(guān)系。

cascade 用來(lái)配置級(jí)聯(lián)操作,有如下取值:

  • ALL:所有操作
  • PERSIST:級(jí)聯(lián)添加
  • MERGE:級(jí)聯(lián)更新
  • REMOVE:級(jí)聯(lián)刪除
  • REFRESH:級(jí)聯(lián)刷新

根據(jù)自己需求選擇合適的就行。

這樣,最終創(chuàng)建出來(lái)的 t_school 表和 t_address 表中,會(huì)分別多出來(lái)一個(gè)字段 address_aid 和 school_sid,這兩個(gè)字段都是外鍵,正是通過(guò)外鍵,將兩張表中不同的記錄關(guān)聯(lián)起來(lái)。

有的人可能不習(xí)慣這種自動(dòng)添加的字段,那也可以自定義該字段,反正該字段總是要有的,自定義的方式如下:

@Data
@Entity
@Table(name = "t_address")
public class Address {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer aid;
private String province;
private String city;
private String area;
private String phone;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "sid",referencedColumnName = "sid")
private School school;
@Column(insertable = false,updatable = false)
private Integer sid;
}
@Data
@Entity
@Table(name = "t_school")
public class School {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer sid;
private String name;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "aid",referencedColumnName = "aid")
private Address address;
@Column(insertable = false,updatable = false)
private Integer aid;
}

在 Address 中自定義一個(gè) sid,并設(shè)置該字段不可添加和修改,然后通過(guò) @JoinColumn 注解去指定關(guān)聯(lián)關(guān)系,@JoinColumn 注解中的 name 表示的是當(dāng)前類中的屬性名,referencedColumnName 表示的則是 School 類中對(duì)應(yīng)的屬性名。

在 School 類中做相似的操作。

最后啟動(dòng)項(xiàng)目去觀察 MySQL 中生成的表。

2. 一對(duì)多

一個(gè)班級(jí)中有多個(gè)學(xué)生,而一個(gè)學(xué)生只屬于一個(gè)班級(jí),我們可以這樣來(lái)定義實(shí)體類:

@Data
@Table(name = "t_student")
@Entity
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer sid;
private String name;
@ManyToOne(cascade = CascadeType.ALL)
private Clazz clazz;
}
@Data
@Table(name = "t_clazz")
@Entity
public class Clazz {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer cid;
private String name;
@OneToMany(cascade = CascadeType.ALL,fetch = FetchType.EAGER)
private List<Student> students;
}

Student 和 Clazz 的關(guān)系是多對(duì)一,用 @ManyToOne 注解,Clazz 和 Student 的關(guān)系是一對(duì)多,用 @OneToMany 注解。

Student 和 Clazz 的關(guān)系是多對(duì)一,將來(lái)的 t_student 表中會(huì)多出來(lái)一個(gè)屬性 clazz_cid,通過(guò)這個(gè)外鍵將 Student 和 Clazz 關(guān)聯(lián)起來(lái)。如果我們不想要自動(dòng)生成的 clazz_cid,那么也可以自定義,方式如下:

@Data
@Table(name = "t_student")
@Entity
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer sid;
private String name;
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "cid")
private Clazz clazz;
@Column(insertable = false,updatable = false)
private Integer cid;
}

定義一個(gè) cid 屬性,并設(shè)置為不可編輯和不可添加,然后通過(guò) @JoinColumn 注解配置 cid 屬性為外鍵。

Clazz 和 Student 的關(guān)系是一對(duì)多,這個(gè)是通過(guò)一個(gè)自動(dòng)生成的第三張表來(lái)實(shí)現(xiàn)的,如下:

3. 測(cè)試

3.1 添加測(cè)試

先來(lái)個(gè)一對(duì)一的添加測(cè)試,如下:

public interface SchoolRepository extends JpaRepository<School,Integer> {
}
@SpringBootTest
class JpaOneToManyApplicationTests {

@Autowired
SchoolRepository schoolRepository;
@Test
void contextLoads() {
School school = new School();
school.setSid(1);
school.setName("哈佛大學(xué)");
Address address = new Address();
address.setAid(1);
address.setProvince("黑龍江");
address.setCity("哈爾濱");
address.setArea("某地");
address.setPhone("123456");
school.setAddress(address);
schoolRepository.save(school);
}

}

在這個(gè)測(cè)試過(guò)程中,關(guān)聯(lián)關(guān)系是由 t_school 一方來(lái)維護(hù)了,因此將來(lái)填充的外鍵是 t_school 中的 aid。添加結(jié)果如下圖:

t_school

t_address

這是一個(gè)簡(jiǎn)單的添加案例。

更新也是調(diào)用 save 方法,更新的時(shí)候會(huì)先判斷這個(gè) id 是否存在,存在的話就更新,不存在就添加。

再來(lái)看班級(jí)的添加,如下:

public interface ClazzRepository extends JpaRepository<Clazz,Integer> {
}
@Autowired
ClazzRepository clazzRepository;
@Test
void test02() {
Clazz c = new Clazz();
c.setCid(1);
c.setName("三年級(jí)二班");
List<Student> students = new ArrayList<>();
Student s1 = new Student();
s1.setSid(1);
s1.setName("javaboy");
students.add(s1);
Student s2 = new Student();
s2.setSid(2);
s2.setName("張三");
students.add(s2);
c.setStudents(students);
clazzRepository.save(c);
}

注意,添加的是班級(jí),所以班級(jí)和學(xué)生之間關(guān)系就由第三張表來(lái)維護(hù),而不是由學(xué)生來(lái)維護(hù)。

3.2 查詢測(cè)試

再來(lái)一個(gè)簡(jiǎn)單的查詢,假設(shè)我們現(xiàn)在想根據(jù)省份來(lái)搜索學(xué)校,如下:

public interface SchoolRepository extends JpaRepository<School,Integer> {
List<School> findSchoolByAddressProvince(String province);
}
@Autowired
SchoolRepository schoolRepository;
@Test
void test01() {
List<School> list = schoolRepository.findSchoolByAddressProvince("黑龍江");
System.out.println("list = " + list);
}

松哥給大家捋一下 Spring Data 如何解析上面自定義的查詢方法:

  • 首先截取掉 findSchoolByAddressProvince 的前綴,剩下 AddressProvince。
  • 檢查 School 是否有 addressProvince 屬性,有就按照該屬性查詢,對(duì)于我們的案例,并沒(méi)有 addressProvince 屬性,所以繼續(xù)下一步。
  • 從右側(cè)駝峰開(kāi)始拆分,拆掉第一個(gè)駝峰后面的內(nèi)容,我們這里拆分之后只剩下 Address 了,判斷 School 是否存在 Address 屬性,不存在就繼續(xù)重復(fù)該步驟,繼續(xù)切掉右側(cè)第一個(gè)駝峰。
  • 在上文案例中,School 中有 address 屬性,所以接下來(lái)就去檢查 address 中是否有 province 屬性,因?yàn)槲覀冞@里只剩下一個(gè) province 了,如果剩下的字符串類似于 provinceAaaBbb 這種,那么繼續(xù)按照第三步去解析。

上面這個(gè)寫(xiě)法有一個(gè)小小的風(fēng)險(xiǎn),假設(shè) School 中剛好就有一個(gè)屬性叫做 addressProvince,那么此時(shí)的分析就會(huì)出錯(cuò)。所以,對(duì)于上面的查詢,我們也可以定義成如下方式:

public interface SchoolRepository extends JpaRepository<School,Integer> {
List<School> findSchoolByAddress_Province(String province);
}

此時(shí)就不會(huì)產(chǎn)生歧義了,系統(tǒng)就知道 province 是 address 的屬性了。

再來(lái)一個(gè)班級(jí)的查詢,如下:

public interface ClazzRepository extends JpaRepository<Clazz,Integer> {
}
@Test
void test03() {
List<Clazz> list = clazzRepository.findAll();
System.out.println("list = " + list);
}

如果在查詢的過(guò)程中,需要對(duì)學(xué)生進(jìn)行排序,可以添加如下屬性:

@Data
@Table(name = "t_clazz")
@Entity
public class Clazz {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer cid;
private String name;
@OneToMany(cascade = CascadeType.ALL,fetch = FetchType.EAGER)
@OrderBy("sid desc")
private List<Student> students;
}

通過(guò) @OrderBy("sid desc") 可以設(shè)置查詢的 student 排序。


責(zé)任編輯:武曉燕 來(lái)源: 江南一點(diǎn)雨
相關(guān)推薦

2009-06-04 16:14:22

Hibernate一對(duì)Hibernate一對(duì)Hibernate多對(duì)

2009-09-22 09:55:58

Hibernate實(shí)例

2009-07-21 17:31:39

iBATIS一對(duì)多映射

2010-04-15 09:09:02

Hibernate

2023-06-12 08:09:01

FlaskSQLAlchemy

2011-03-25 10:49:30

Join一對(duì)多

2010-07-07 08:33:09

SQL Server學(xué)

2020-02-12 11:34:56

架構(gòu)平滑上云機(jī)房遷移

2020-06-23 14:28:24

MySQL商品數(shù)據(jù)

2009-06-24 15:51:47

Entity Bean一對(duì)多映射

2012-03-21 11:43:41

JavaHibernate

2022-10-08 11:40:18

Receive阻塞Trigger

2009-06-04 10:34:19

Hibernate一對(duì)一對(duì)多關(guān)系配置

2009-06-03 16:27:27

Hibernate一對(duì)一關(guān)系

2009-06-03 16:18:16

Hibernate關(guān)系代碼實(shí)例

2012-02-08 13:34:08

HibernateJava

2019-05-12 14:10:07

物聯(lián)網(wǎng)DDOS網(wǎng)絡(luò)攻擊

2009-06-26 10:15:54

面試HR

2009-09-23 10:37:50

Hibernate一對(duì)

2020-12-07 09:26:16

AI 數(shù)據(jù)人工智能
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)