欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

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

发布时间:2024/9/30 编程问答 41 豆豆
生活随笔 收集整理的这篇文章主要介绍了 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 @GeneratedValuepublic 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 {//事务管理@PersistenceContextprivate EntityManager em;//JPA一对多测试类@Overridepublic 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 @GeneratedValuepublic 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 @GeneratedValuepublic 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一对多测试类@Overridepublic 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 @GeneratedValuepublic 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;}@Overridepublic int hashCode() {final int prime = 31;int result = 1;result = prime * result + ((id == null) ? 0 : id.hashCode());return result;}@Overridepublic 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 @GeneratedValuepublic 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多对多测试类:没有建立关系联系的添加@Overridepublic void jpaTest() {//没有建立关系联系的添加em.persist(new Student("小张"));em.persist(new Teacher("李老师"));} //JPA多对多测试类:建立学生跟老师的联系@Overridepublic void jpaTest() {//建立学生和老师的关系Student student=em.find(Student.class, 15);student.addTeacher(em.getReference(Teacher.class, 16));} //JPA多对多测试类:删除学生跟老师的联系@Overridepublic void jpaTest() {//删除学生跟老师的联系Student student=em.find(Student.class, 15);student.removeTeacher(em.getReference(Teacher.class, 16));} //JPA多对多测试类:删除对象:只删除教师//直接不接触外键,直接删除老师,这种方式删除不了,被维护端没有权限删除外键,抛异常@Overridepublic void jpaTest() {em.remove(em.getReference(Teacher.class, 16));} //JPA多对多测试类:删除对象:只删除教师//先解除学生与老师的关系,再删除教师对象@Overridepublic void jpaTest() {Student student=em.find(Student.class, 15);Teacher teacher=em.getReference(Teacher.class, 16);student.removeTeacher(teacher);em.remove(teacher);} //JPA多对多测试类:删除对象:学生,并删除第三表中的记录,不删除老师//关系维护端有权限删除外键@Overridepublic 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;}@Overridepublic 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;}@Overridepublic 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;//联合主键的实体标识符@EmbeddedIdpublic 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、联合主键测试类:

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

 

 

总结

以上是生活随笔为你收集整理的JPA规范:一对多、一对一、多对多的双向关联与级联操作以及JPA联合主键的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。