【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.mzph.cn/diannao/40349.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

从涟漪到波浪:资产代币化的变革力量

原文标题&#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;如划痕、残胶、异色、杂物等。系统支持多种探头形态&…

【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做不到的…

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…

前端三件套开发模版——产品介绍页面

今天有空&#xff0c;使用前端三件套html、css、js制作了一个非常简单的产品制作页面&#xff0c;与大家分享&#xff0c;希望可以满足大家应急的需求。本页面可以对产品进行“抢购”、对产品进行介绍&#xff0c;同时可以安排一张产品的高清大图&#xff0c;我也加入了页面的背…

JAVA实现二分查找,斐波那契数列,深度优先搜索详情教程【包含代码】

本人详解 作者:王文峰,参加过 CSDN 2020年度博客之星,《Java王大师王天师》 公众号:JAVA开发王大师,专注于天道酬勤的 Java 开发问题中国国学、传统文化和代码爱好者的程序人生,期待你的关注和支持!本人外号:神秘小峯 山峯 转载说明:务必注明来源(注明:作者:王文峰…

Ubuntu查看opencv版本c++

✗命令行中直接输入&#xff1a; pkg-config --modversion opencv✔命令行中直接输入&#xff1a; pkg-config --modversion opencv4注解&#xff1a;附上在markdown中打勾&#xff0c;对号和打叉。使用时将&和#之间的空格去掉&#xff0c;这里只是为了不让CSDN自动转换才…

vue3单个页面进行防抖节流

防抖 <template><button id"submitButton" ref"submitButton">GET</button> </template><script lang"ts" setup> import { ref, onMounted } from vue;// 防抖函数 function debounce(func: () > void, dela…

小白尝试某程机票信息爬取

实训课需要机票数据集&#xff0c;网上没有&#xff0c;所以我选择爬取数据 此过程可谓经历的九九八十一难&#xff0c;也参考了不少大佬的文章&#xff0c;在此特别记录一下 弯路不多说&#xff0c;我直接讲成功的方法 找到请求url 通过控制台&#xff0c;最后确认下面的 …

基于Java中的SSM框架实现物流管理系统项目【项目源码+论文说明】

基于Java中的SSM框架实现物流管理系统演示 摘要 企业的发展离不开物流的运输&#xff0c;在一个大型的企业中&#xff0c;商品的生产和建设&#xff0c;推广只是前期的一些工作&#xff0c;在后期的商品销售和物流方面的建立&#xff0c;才能让一个企业得到大力的发展。 企业…

基于Linux/ARM/单片机利用状态机对多个按键进行扫描实现短按或者长按

1&#xff09;Linux/ARM/单片机入门级按键扫描程序设计&#xff0c;分享给将要学习或者正在学习Linux/ARM/单片机开发的同学。 2&#xff09;内容属于原创&#xff0c;若转载&#xff0c;请说明出处。 3&#xff09;提供相关问题有偿答疑和支持。 学习Linux/ARM/单片机的同学…