【Spring Boot】關系映射開發(一):一對一映射

關系映射開發(一):一對一映射

  • 1.認識實體間關系映射
    • 1.1 映射方向
    • 1.2 ORM 映射類型
  • 2.實現 “一對一” 映射
    • 2.1 編寫實體
      • 2.1.1 新建 Student 實體
      • 2.1.2 新建 Card 實體
    • 2.2 編寫 Repository 層
      • 2.2.1 編寫 Student 實體的 Repository
      • 2.2.2 編寫 Card 實體的 Repository
    • 2.3 編寫 Service 層
      • 2.3.1 編寫 Student 的 Service 層
      • 2.3.2 編寫 Card 的 Service 層
    • 2.4 編寫 Service 實現
      • 2.4.1 編寫 Student 實體的 Service 實現
      • 2.4.2 編寫 Card 實體的 Service 實現
    • 2.5 編寫測試
  • 3.單向 / 雙向 OneToOne
    • 3.1 單向一對一關系的擁有端
    • 3.2 單向一對一關系的接收端
    • 3.3 雙向一對一關系的接收端

1.認識實體間關系映射

對象關系映射object relational mapping)是指通過將對象狀態映射到數據庫列,來開發和維護對象和關系數據庫之間的關系。它能夠輕松處理(執行)各種數據庫操作,如插入、更新、 刪除等。

1.1 映射方向

ORM 的映射方向是表與表的關聯(join),可分為兩種。

  • 單向關系:代表一個實體可以將屬性引用到另一個實體。即只能從 A 表向 B 表進行聯表查詢。
  • 雙向關系:代表每個實體都有一個關系字段(屬性)引用了其他實體。

1.2 ORM 映射類型

  • 一對一@OneToOne):實體的每個實例與另一個實體的單個實例相關聯。
  • 一對多@OneToMany):一個實體的實例可以與另一個實體的多個實例相關聯。
  • 多對一@ManyToOne): —個實體的多個實例可以與另一個實體的單個實例相關聯。
  • 多對多@ManyToMany):—個實體的多個實例可能與另一個實體的多個實例有關。在這個映射中,任何一方都可以成為所有者方。

2.實現 “一對一” 映射

一對一 映射首先要確定實體間的關系,并考慮表結構,還要考慮實體關系的方向性。

若為 雙向關聯,則在保存實體關系的實體中要配合注解 @JoinColumn;在沒有保存實體關系的實體中,要用 mappedBy 屬性明確所關聯的實體。

下面通過實例來介紹如何構建一對一的關系映射。

2.1 編寫實體

2.1.1 新建 Student 實體

package com.example.demo.entity;import lombok.Data;
import javax.persistence.*;@Entity
@Data
@Table(name = "stdu")
public class Student {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private long id;private String name;@Column(columnDefinition = "enum('male','female')")private String sex;/*** Description:* 建立集合,指定關系是一對一,并且申明它在cart類中的名稱* 關聯的表為card表,其主鍵是id* 指定外鍵名為card_id*/@OneToOne(cascade = CascadeType.ALL)@JoinColumn(name = "card_id")private Card card;
}

在這里插入圖片描述

2.1.2 新建 Card 實體

package com.example.demo.entity;import lombok.Data;
import javax.persistence.*;@Entity
@Table(name = "card")
@Data
public class Card {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private long id;private Integer num;
}

在這里插入圖片描述

2.2 編寫 Repository 層

2.2.1 編寫 Student 實體的 Repository

package com.example.demo.repository;import com.example.demo.entity.Student;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;import javax.transaction.Transactional;public interface StudentRepository extends JpaRepository<Student, Long> {Student findById(long id);Student deleteById(long id);
}

2.2.2 編寫 Card 實體的 Repository

package com.example.demo.repository;import com.example.demo.entity.Card;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;public interface CardRepository extends JpaRepository<Card, Long>, JpaSpecificationExecutor<Card> {Card findById(long id);
}

2.3 編寫 Service 層

2.3.1 編寫 Student 的 Service 層

package com.example.demo.service;import com.example.demo.entity.Student;
import java.util.List;public interface StudentService {public List<Student> getStudentlist();public Student findStudentById(long id);
}

2.3.2 編寫 Card 的 Service 層

package com.example.demo.service;import com.example.demo.entity.Card;
import java.util.List;public interface CardService {public List<Card> getCardList();public Card findCardById(long id);
}

2.4 編寫 Service 實現

2.4.1 編寫 Student 實體的 Service 實現

package com.example.demo.service.impl;import com.example.demo.entity.Student;
import com.example.demo.repository.StudentRepository;
import com.example.demo.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.List;@Service
public class StudentServiceImpl implements StudentService {@Autowiredprivate StudentRepository studentRepository;@Overridepublic List<Student> getStudentlist() {return studentRepository.findAll();}@Overridepublic Student findStudentById(long id) {return studentRepository.findById(id);}
}

2.4.2 編寫 Card 實體的 Service 實現

package com.example.demo.service.impl;import com.example.demo.entity.Card;
import com.example.demo.repository.CardRepository;
import com.example.demo.service.CardService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.List;@Service
public class CardServiceImpl implements CardService {@Autowiredprivate CardRepository cardRepository;@Overridepublic List<Card> getCardList() {return cardRepository.findAll();}@Overridepublic Card findCardById(long id) {return cardRepository.findById(id);}
}

2.5 編寫測試

完成了上面的工作后,就可以測試它們的關聯關系了。

package com.example.demo.entity;import com.example.demo.repository.CardRepository;
import com.example.demo.repository.StudentRepository;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;import static org.junit.Assert.*;@SpringBootTest
@RunWith(SpringRunner.class)
public class oneToOneTest {@Autowiredprivate StudentRepository studentRepository;@Autowiredprivate CardRepository cardRepository;@Testpublic void testOneToOne() {Student student1 = new Student();student1.setName("趙大偉");student1.setSex("male");Student student2 = new Student();student2.setName("趙大寶");student2.setSex("male");Card card1 = new Card();card1.setNum(422802);student1.setCard(card1);studentRepository.save(student1);studentRepository.save(student2);Card card2 = new Card();card2.setNum(422803);cardRepository.save(card2);/*** Description: 獲取添加之后的id*/Long id = student1.getId();/*** Description: 刪除剛剛添加的student1*/studentRepository.deleteById(id);}
}

首先,注釋掉 studentRepository.deleteById(id);,看一下數據庫。因為級聯的原因,在運行 studentRepository.save(student1); 時,就保存了 card1,所以不需要像 cardRepository.save(card2); 一樣運行 cardRepository.save(card1);

在這里插入圖片描述
在這里插入圖片描述
運行代碼,在控制臺輸出如下測試結果:

在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

可以看到,同時在兩個表 stducard 中添加了內容,然后刪除了剛添加的有關聯的 stducard 表中的值。如果沒有關聯,則不刪除。

🚀 在雙向關系中,有一方為關系的 發出端,另一方是關系的 反端,即 Inverse 端(接收端)。對于雙向的一對一關系映射,發出端和接收端都要使用注解 @OneToOne,同時定義一個接收端類型的字段屬性和 @OneToOne 注解中的 mappedBy 屬性。這個在雙向關系的接收端是必需的。

3.單向 / 雙向 OneToOne

單向一對一 是關聯關系映射中最簡單的一種,簡單地說就是可以從關聯的一方去查詢另一方,卻不能反向查詢。我們用下面的例子來舉例說明,清單 1 中的 Person 實體類和清單 2 中的 Address 類就是這種單向的一對一關系,我們可以查詢一個 Person 的對應的 Address 的內容,但是我們卻不能由一個 Address 的值去查詢這個值對應的 Person。

3.1 單向一對一關系的擁有端

@Entity 
public class Person implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String name; private int age; @OneToOne private Address address; // Getters & Setters 
}

3.2 單向一對一關系的接收端

@Entity 
public class Address implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String street; private String city; private String country;// Gettes & Setters 
}

在這里插入圖片描述
從上面的 ER 圖可以看出,這種單向的一對一關系在數據庫中是以外鍵的形式被映射的。其中關系的 發出端 存儲一個指向關系的接收端的一個外鍵。在這個例子中 person 表中的 ADDRESS_ID 就是指向 address 表的一個外鍵,缺省情況下這個外鍵的字段名稱,是以它指向的表的名稱加下劃線 _ID 組成的。當然我們也可以根據我們的喜好來修改這個字段,修改的辦法就是使用 @JoinColumn 這個注解。在這個例子中我們可以將這個注解注釋在 Person 類中的 Address 屬性上去。

3.3 雙向一對一關系的接收端

@Entity 
public class Address implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String street; private String city; private String country; @OneToOne(mappedBy = "address") private Person person; // Gettes & Setters 
}

雙向關系有一方為關系的擁有端,另一方是關系的接收端(反端),也就是 Inverse 端。在這個例子中 Person 擁有這個關系,而 Address 就是關系的 Inverse 端。Address 中我們定義了一個 person 屬性,在這個屬性上我們使用了 @OneToOne 注解并且定義了它的 mappedBy 屬性,這個在雙向關系的 Inverse 端是必需的。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/40349.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/40349.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/40349.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

DFS,BFS最短路,樹與圖的深度/廣度優先遍歷,拓撲排序

DFS 例題&#xff1a;排列數字 在排列組合問題中&#xff0c;每個位置需要嘗試多個不同的數字組合&#xff0c;需要回溯以嘗試不同的可能性。因此&#xff0c;需要顯式地恢復現場&#xff08;撤銷標記&#xff09;&#xff0c;以確保每個可能的路徑都被探索。 #include <b…

從漣漪到波浪:資產代幣化的變革力量

原文標題&#xff1a;《From ripples to waves: The transformational power of tokenizing assets》撰文&#xff1a;Anutosh Banerjee&#xff0c;Matt Higginson&#xff0c;Julian Sevillano&#xff0c;Matt Higginson編譯&#xff1a;Chris&#xff0c;Techub News本文來…

還是NC,項目代碼開源|scRNA+bulkRNA+因子分析驗證地塞米松治療Covid19

說在前面 平時發文章的話&#xff0c;做藥物用的大多都是僅僅是GEO的bulkRNA&#xff0c;有人的有鼠的&#xff0c;然后做做流水線分析&#xff0c;最后面PCR。今天看一篇發NC的工作量&#xff0c;怎么用轉錄組分析做藥物的轉化免疫學 這篇文章作者已經上傳Github了&#xff…

LabVIEW自動探頭外觀檢測

開發了一套基于LabVIEW的軟件系統&#xff0c;結合視覺檢測技術&#xff0c;實現探頭及連接器外觀的自動檢測。通過使用高分辨率工業相機、光源和機械手臂&#xff0c;系統能夠自動定位并檢測探頭表面的細微缺陷&#xff0c;如劃痕、殘膠、異色、雜物等。系統支持多種探頭形態&…

Spark SQL----數據類型

Spark SQL----數據類型 一、支持的數據類型二、浮點特殊值三、正負無窮語義四、NaN語義五、例子 一、支持的數據類型 Spark SQL和DataFrames支持以下數據類型&#xff1a; Numeric類型 ByteType&#xff1a;表示1字節的帶符號整數。數字的范圍從-128到127。ShortType&#xf…

【C++ OpenCV】機器視覺-二值圖像和灰度圖像的膨脹、腐蝕、開運算、閉運算

原圖 結果圖 //包含頭文件 #include <opencv2/opencv.hpp>//命名空間 using namespace cv; using namespace std;//全局函數聲明部分//我的腐蝕運算 Mat Erode(Mat src, Mat Mask, uint32_t x0, uint32_t y0) {uint32_t x 0, y 0;Mat dst(src.rows, src.cols, CV_8U…

如何在忘記密碼的情況下重置Realme手機?

歡迎閱讀我們關于如何在有或沒有密碼的情況下重置Realme手機的綜合指南。無論您是忘記了密碼&#xff0c;還是只是需要將設備恢復到出廠設置&#xff0c;我們都會為您提供所需的專業提示和技術專長。 發現分步說明、專家提示和行之有效的方法&#xff0c;輕松重新控制您的 Rea…

Hadoop3:集群壓測-讀寫性能壓測

一、準備工作 首先&#xff0c;我們要知道&#xff0c;平常所說的網速和文件大小的MB是什么關系。 100Mbps單位是bit&#xff1b;10M/s單位是byte ; 1byte8bit&#xff0c;100Mbps/812.5M/s。 測試 配置102、103、104虛擬機網速 102上用Python開啟一個文件下載服務&#x…

Alpha2:使用深度強化學習挖掘公式化的超額收益因子(附論文及源代碼)

原創文章第577篇&#xff0c;專注“AI量化投資、世界運行的規律、個人成長與財富自由"。 今天說說因子挖掘&#xff0c;我們之前交付的Deap遺傳算法因子挖掘&#xff0c;大家可以前往溫習一下&#xff1a; 源碼發布Quantlab4.2&#xff0c;Deap因子挖掘|gplearn做不到的…

【編譯】strip去除符號表

文章目錄 1. 去除符號表2. dbg信息的作用2.1 靜態編譯2.2 動態庫編譯方式 1. 去除符號表 作用&#xff1a;去除符號表可以極大縮小發布的二進制大小&#xff08;有時候可以縮小一半&#xff09; 去除手段共兩種&#xff1a; 直接使用strip命令使用objcopy(更常用&#xff09;…

多線程編程的基本概念,C++標準庫中的多線程支持(std::thread,std::async),如何處理線程同步和并發問題。

多線程編程在現代計算機系統中非常重要&#xff0c;因為它能夠使程序同時執行多個操作&#xff0c;提高計算效率。以下是多線程編程的基本概念及如何在C標準庫中使用std::thread和std::async進行多線程編程&#xff0c;同時處理線程同步和并發問題。 多線程編程的基本概念 線程…

K8S學習教程(二):在 PetaExpress KubeSphere容器平臺部署高可用 Redis 集群

前言 Redis 是在開發過程中經常用到的緩存中間件&#xff0c;為了考慮在生產環境中穩定性和高可用&#xff0c;Redis通常采用集群模式的部署方式。 在制定Redis集群的部署策略時&#xff0c;常規部署在虛擬機上的方式配置繁瑣并且需要手動重啟節點&#xff0c;相較之下&#…

十款絢麗的前端 CSS 菜單導航動畫

CSS漢堡菜單是一種非常流行的PC端和移動端web菜單風格&#xff0c;特別是移動端&#xff0c;這種風格的菜單應用更為廣泛。這款菜單便非常適合在手機App上使用&#xff0c;它的特點是當頂部菜單彈出時&#xff0c;頁面內容將會配合菜單出現適當的聯動&#xff0c;讓整個頁面變得…

關于linux捕捉鼠標事件的方法

網上找了很多方法&#xff0c;都比較雜亂。這篇文章專注于讀取鼠標的動作&#xff1a;左鍵、右鍵、中鍵、滾輪。 linux的設備都以文件形式存放&#xff0c;要讀取鼠標&#xff0c;有兩種方法&#xff0c;一種是通過/dev/input/mice&#xff0c;一種是通過/dev/input/eventx (x…

探索線程安全:HashMap 的四種使用技巧

這篇文章&#xff0c;我們聊聊線程安全使用 HashMap 的四種技巧。 1 方法內部&#xff1a;每個線程使用單獨的 HashMap 如下圖&#xff0c;tomcat 接收到到請求后&#xff0c;依次調用控制器 Controller、服務層 Service 、數據庫訪問層的相關方法。 每次訪問服務層方法 serv…

vue H5頁面video 視頻流自動播放, 解決ios不能自動播放問題

視頻組件 <videostyle"width: 100%; height: 100%;object-fit: fill"class"player"refplayer_big_boxcontrolspreloadautoplay //自動播放muted //是否靜音playsinline"true"x5-playsinline""webkit-playsinline"tru…

[Linux安全運維] Linux用戶以及權限管理

Linux用戶以及權限管理 Linux用戶和組 用戶信息文件pasawd /etc/passwd文件用于存儲用戶的信息 :用于分割不同的字段信息 字段示例&#xff08;第一行&#xff09;含義說明1root用戶名2x密碼占位符x代表用戶有密碼存儲在shadow文件中無內容代表用戶登錄系統不需要密碼30UID…

梧桐數據庫:存算分離和存算一體架構的分布式數據庫技術分析

摘要&#xff1a; 隨著數據量的不斷增長和對數據處理性能的要求越來越高&#xff0c;分布式數據庫技術成為了數據存儲和處理的重要解決方案。存算分離和存算一體是兩種常見的分布式數據庫架構&#xff0c;它們在數據存儲和計算方面有著不同的特點和優勢。本文將對存算分離和存算…

Spring源碼(一) 如何閱讀 Spring 源碼

學習 Spring 的源碼&#xff0c;也可以通過 SpringBoot 搭環境。 不管是什么源碼&#xff0c;最好寫個 demo&#xff0c;跑起來&#xff0c;然后從常用的類和方法入手&#xff0c;跟蹤調試。 配置對象 新建一個 SpringBoot 的項目&#xff0c; 詳情見&#xff1a; https://b…

FreeRTOS 中 vListInsertEnd 函數詳解

在 FreeRTOS 中&#xff0c;vListInsertEnd 函數用于將新項插入到指定列表的尾部&#xff08;但實際行為是插入到一個特定的索引位置之前&#xff09;。FreeRTOS 使用雙向鏈表&#xff08;doubly linked list&#xff09;來管理任務和其他系統對象&#xff0c;這樣可以高效地插…