JPA规范:一对多、一对一、多对多的双向关联与级联操作以及JPA联合主键

JPA规范:一对多、一对一、多对多的双向关联与级联操作以及JPA联合主键

通常在企业开发中,开发Dao层有两种做法: 
(1)先建表,后再根据表来编写配置文件和实体bean。使用这种方案的开发人员受到了传统数据库建模的影响。 
(2)先编写配置文件和实体bean,然后再生成表,使用这种方案的开发人员采用的是领域建模思想,这种思想相对前一种思想更加OOP。

建议使用第二种(领域建模思想),从软件开发来想,这种思想比第一种思想更加面向对象。 领域建模思想也是目前比较新的一门建模思想,第一种是传统的建模思想,已经有10来年的发展历程了,而领域建模思想是近几年才兴起的,这种思想更加的面向对象。

 

 

一、一对多双向关联与级联操作:

以订单类和订单商品类为例:

多的一方为关系维护端,关系维护端负责外键记录的更新,关系被维护端是没有权利更新外键记录。

1、订单类:

@Entity
public class Orders {
	private String orderid;
	private Float amount = 0f;
	private Set<OrderItem> items=new HashSet<OrderItem>();
	
	@Id @Column(length=12)
	public String getOrderid() {
		return orderid;
	}
	public void setOrderid(String orderid) {
		this.orderid = orderid;
	}
	
	@Column(nullable=false)
	public Float getAmount() {
		return amount;
	}
	public void setAmount(Float amount) {
		this.amount = amount;
	}
	
	//REFRESH,级联刷新(调用refresh方法才会起作用);PERSIST,级联保存(persist);
	//MERGE,级联更新(merge方法);REMOVE,级联删除(remove方法);
	//级联:cascade={CascadeType.ALL})如果要使用上面四项的使用,可以使用ALL来代替
	//@OneToMany默认行为是延迟加载
	//mappedBy:指定关系被维护端,指定OrderItem里面的order,相当于hibernate的inverse放弃维护
	@OneToMany(cascade={CascadeType.REFRESH,CascadeType.PERSIST,CascadeType.MERGE,CascadeType.REMOVE}
	,fetch=FetchType.LAZY,mappedBy="orders")
	public Set<OrderItem> getItems() {
		return items;
	}
	public void setItems(Set<OrderItem> items) {
		this.items = items;
	}
	
	public void addOrderItem(OrderItem orderItem){
		orderItem.setOrders(this);
		this.items.add(orderItem);
	}
}

2、订单列表类:

@Entity
public class OrderItem {
	private Integer id;
	private String productName;
	private Float sellPrice = 0f;
	
	private Orders orders;//对应Order类里面指定的关系被维护端
	
	@Id @GeneratedValue
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	
	@Column(length=40,nullable=false)
	public String getProductName() {
		return productName;
	}
	public void setProductName(String productName) {
		this.productName = productName;
	}
	
	@Column(nullable=false)
	public Float getSellPrice() {
		return sellPrice;
	}
	public void setSellPrice(Float sellPrice) {
		this.sellPrice = sellPrice;
	}
	
	//默认立即加载
	//optional=true,选项允许为null,false时,不能为null
	@ManyToOne(cascade={CascadeType.MERGE,CascadeType.REFRESH},optional=false)
	@JoinColumn(name="order_id")//设置外键名称
	public Orders getOrders() {
		return orders;
	}
	public void setOrders(Orders orders) {
		this.orders = orders;
	}
}

3、一对多的测试类:

//JPA的Dao层
@Transactional
public class JpaDaoImpl implements JpaDao {
	
	//事务管理
	@PersistenceContext
	private EntityManager em;
	
	//JPA一对多测试类
	@Override
	public void jpaTest() {
		Orders orders=new Orders();
		orders.setAmount(34f);
		orders.setOrderid("999");
		
		OrderItem orderItem1=new OrderItem();
		orderItem1.setProductName("篮球");
		orderItem1.setSellPrice(150f);
		OrderItem orderItem2=new OrderItem();
		orderItem2.setProductName("足球");
		orderItem2.setSellPrice(90f);
		
		orders.addOrderItem(orderItem1);
		orders.addOrderItem(orderItem2);
		
		em.merge(orders);
	}
}

由于配置了事务管理,这里就不需要手动开启、提交事务和关闭资源等重复的代码,直接交由事务进行管理。

具体配置步骤可以参看这篇博客:https://blog.csdn.net/a745233700/article/details/81415550

 

 

二、一对一双向关联与级联操作:

以身份证类和人为例:

1、Persion类:

@Entity
public class Person {
	public Person() {
	}
	public Person(String name) {
		this.name=name;
	}
	
	private Integer id;
	private String name;
	private IDcard idcard;
	 
	@Id @GeneratedValue
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	
	@Column(length=10,nullable=false)
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
        //一对一配置
	@OneToOne(optional=false,cascade={CascadeType.ALL})
	@JoinColumn(name="idcard_id")
	public IDcard getIdcard() {
		return idcard;
	}
	public void setIdcard(IDcard idcard) {
		this.idcard = idcard;
	}
}

2、IDcard类:

@Entity
public class IDcard {
	public IDcard() {}
	public IDcard(String cardno) {
		this.cardno = cardno;
	}

	private Integer id;
	private String cardno;
	private Person person;
	
	@Id @GeneratedValue
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	
	@Column(length=18,nullable=false)
	public String getCardno() {
		return cardno;
	}
	public void setCardno(String cardno) {
		this.cardno = cardno;
	}
	
	//一对一配置:
	@OneToOne(mappedBy="idcard",cascade={CascadeType.PERSIST,CascadeType.MERGE,CascadeType.REFRESH})
	public Person getPerson() {
		return person;
	}
	public void setPerson(Person person) {
		this.person = person;
	}
}

3、一对一测试类:

	//JPA一对多测试类
	@Override
	public void jpaTest() {
		
		Person person=new Person("小张");		
		person.setIdcard(new IDcard("448xxx1990xxxx1234"));
		
		em.persist(person);
	}

 

 

三、多对多双向关联与级联操作:

以教师类和学生类为例:

1、教师类:

//老师为关系被维护端
@Entity
public class Teacher {
	public Teacher(){}
	public Teacher(String name) {
		this.name = name;
	}
	private Integer id;
	private String name;
	private Set<Student> students=new HashSet<Student>();
	
	@Id @GeneratedValue
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	
	@Column(length=10,nullable=false)
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
	@ManyToMany(cascade=CascadeType.REFRESH,mappedBy="teachers")
	public Set<Student> getStudents() {
		return students;
	}
	public void setStudents(Set<Student> students) {
		this.students = students;
	}
	
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((id == null) ? 0 : id.hashCode());
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Teacher other = (Teacher) obj;
		if (id == null) {
			if (other.id != null)
				return false;
		} else if (!id.equals(other.id))
			return false;
		return true;
	}
}

2、学生类:

//学生为关系维护端
@Entity
public class Student {
	public Student(){}
	public Student(String name) {
		this.name = name;
	}
	
	private Integer id;
	private String name;
	private Set<Teacher> teachers=new HashSet<Teacher>();
	
	@Id @GeneratedValue
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	
	@Column(length=10,nullable=false)
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
	@ManyToMany(cascade=CascadeType.REFRESH)
	@JoinTable(name="student_teacher",//设置第三张表的表名
	inverseJoinColumns=@JoinColumn(name="teacher_id"),//设置被维护端在第三张表中的外键名称
	joinColumns=@JoinColumn(name="student_id"))//设置维护端在第三张表中的外键名称
	public Set<Teacher> getTeachers() {
		return teachers;
	}
	public void setTeachers(Set<Teacher> teachers) {
		this.teachers = teachers;
	}
	
	public void addTeacher(Teacher teacher){
		this.teachers.add(teacher);
	}
	
	public void removeTeacher(Teacher teacher){
		if(this.teachers.contains(teacher)){
			this.teachers.remove(teacher);
		}
	}
}

3、多对多测试类:

	//JPA多对多测试类:没有建立关系联系的添加
	@Override
	public void jpaTest() {
		
		//没有建立关系联系的添加
		em.persist(new Student("小张"));
		em.persist(new Teacher("李老师"));
	}
	//JPA多对多测试类:建立学生跟老师的联系
	@Override
	public void jpaTest() {
		
		//建立学生和老师的关系
		Student student=em.find(Student.class, 15);
		student.addTeacher(em.getReference(Teacher.class, 16));
	}
	//JPA多对多测试类:删除学生跟老师的联系
	@Override
	public void jpaTest() {
		
		//删除学生跟老师的联系
		Student student=em.find(Student.class, 15);
		student.removeTeacher(em.getReference(Teacher.class, 16));
	}
	//JPA多对多测试类:删除对象:只删除教师
	//直接不接触外键,直接删除老师,这种方式删除不了,被维护端没有权限删除外键,抛异常
	@Override
	public void jpaTest() {
		
		em.remove(em.getReference(Teacher.class, 16));
	}
	//JPA多对多测试类:删除对象:只删除教师
	//先解除学生与老师的关系,再删除教师对象
	@Override
	public void jpaTest() {
		
		Student student=em.find(Student.class, 15);
		Teacher teacher=em.getReference(Teacher.class, 16);
		student.removeTeacher(teacher);
		em.remove(teacher);
	}
	//JPA多对多测试类:删除对象:学生,并删除第三表中的记录,不删除老师
	//关系维护端有权限删除外键
	@Override
	public void jpaTest() {
		
		em.remove(em.getReference(Student.class, 15));
	}

 

 

四、联合主键:

以飞机航线为例:两个城市决定一条航线。

1、联合主键的三个要求:

(1)必须定义无参构造函数;

(2)必须实现序列化接口Serializable;

(3)必须重写hashCode()和equals()方法。

2、AirLinkPK联合主键类:

/*联合主键的三个要求:
1.必须定义无参构造函数
2.必须实现序列化接口Serializable
3.必须重写hashCode()和equals()方法
*/
@Embeddable
public class AirLinePK implements Serializable {		
	public AirLinePK(){}
	public AirLinePK(String startCity, String endCity) {
		this.startCity = startCity;
		this.endCity = endCity;
	}
	
	private String startCity;//开始城市
	private String endCity;//结束城市
	
	@Column(length=3)
	public String getStartCity() {
		return startCity;
	}
	public void setStartCity(String startCity) {
		this.startCity = startCity;
	}
	
	@Column(length=3)
	public String getEndCity() {
		return endCity;
	}
	public void setEndCity(String endCity) {
		this.endCity = endCity;
	}
	
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((endCity == null) ? 0 : endCity.hashCode());
		result = prime * result + ((startCity == null) ? 0 : startCity.hashCode());
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		AirLinePK other = (AirLinePK) obj;
		if (endCity == null) {
			if (other.endCity != null)
				return false;
		} else if (!endCity.equals(other.endCity))
			return false;
		if (startCity == null) {
			if (other.startCity != null)
				return false;
		} else if (!startCity.equals(other.startCity))
			return false;
		return true;
	}
}

3、AirLine类:

@Entity
public class AirLine {
	
	public AirLine(){}
	public AirLine(AirLinePK id) {
		this.id = id;
	}
	public AirLine(String startCity,String endCity,String name){
		this.id=new AirLinePK(startCity,endCity);
		this.name=name;
	}
	
	private AirLinePK id;
	private String name;
	
	//联合主键的实体标识符
	@EmbeddedId
	public AirLinePK getId() {
		return id;
	}
	public void setId(AirLinePK id) {
		this.id = id;
	}
	
	@Column(length=20)
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
}

3、联合主键测试类:

	//联合主键测试类
	@Override
	public void jpaTest() {
		
		em.persist(new AirLine("PEK","SHA","北京飞上海"));
	}

 

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/114704.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • Linux入门命令_零基础自学吉他的步骤

    Linux入门命令_零基础自学吉他的步骤Linux入门基础命令教程linux用户识别查看文件与目录命令三级目录linux用户识别这里我就不详细介绍什么是linux,相比你来看文章的都知道什么是linux。linux用户分为两种,分别是管理员用户和普通用户,当我们登录linux的时候会看到如下图第一部分是用户名@demon是主机名/当前所在路径root是管理员用户demon是普通用户可以看到他们的区别在于最后的字符,#是管理员用户的意思,$是普通用户的意思。查看文件与目录命令1.pwd查看当前所在的目录如图

    2022年10月10日
  • win10中修改mac地址(总有一款适合你)

    win10中修改mac地址(总有一款适合你)我的解决办法如下:先上图:下面转自:Win10秘笈:两种方式修改网卡物理地址(MAC)https://www.ithome.com/html/win10/244510.htm在修改之前,可以先确定一下要修改的网卡MAC地址,查询方法有很多种,比如:1、在设置→网络和Internet→WLAN/以太网,如下图——2、在控制

  • 转录因子调控基因表达_转录因子的转录激活域

    转录因子调控基因表达_转录因子的转录激活域基因转录调控网络——转录因子调控网络分析转录因子(TranscriptionFactors,TFs)是指能够以序列特异性方式结合DNA并且调节转录的蛋白质。转录因子通过识别特定的DNA序列来控制染色质和转录,以形成指导基因组表达的复杂系统。转录水平的调控是基因调控的重要环节,其中转录因子(TranscriptionFactor,TF)和转录因子结合位点(TranscriptionFactorBindingSite,TFBS)是转录调控的重要组成部分。基因转录调控网络由于其可以直观地显示基

    2022年10月28日
  • 【C语言的日常实践(十四)】constkeyword详细解释

    【C语言的日常实践(十四)】constkeyword详细解释

  • Linux中PLSQL视频,PLSQL使用视频教程:PLSQL的使用方法「建议收藏」

    Linux中PLSQL视频,PLSQL使用视频教程:PLSQL的使用方法「建议收藏」不少小伙伴对PLSQL的应用还不是很了解,大家不必担心,在PLSQL使用视频教程中会告诉大家如何使用PLSQL。初次登录PLSQL:登录信息保存功能设置:这样第一次通过用户名/密码登录某数据库后,下次就不用再输入用户名/密码了。进入PLSQL后切换数据库连接:PLSQL中编写SQL语句并执行注意:选中要执行的语句,再执行,否则将执行所有SQL语句。执行快捷键为:F8有的老版本执行语句的按钮是这个样…

  • springboot实战第四章-Spring MVC 基本配置

    springboot实战第四章-Spring MVC 基本配置

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号