jpa之hibernate4.2.4之双向关联之一对一、一对多、多对多

      hibernate版本4.2.4

     oracle 版本11g

本文主要涉及到以下几个知识点:

    1.双向关联之一对一

    2.双向关联之一对多

    3.双向关联之多对多


对于双向关联其实有几个步骤(个人总结,如有不对,欢迎吐槽)

    a.要建立双方关联,首先要各自拥有对方对象

    b.指明关系维护端与关系被维护端 指明两者的级联关系

   c.指明外键(或者关联表)

   d.添加数据(向关系维护端添加对象,相当于向表中插入数据;向关系维护端删除对象,相当于向表中删除数据)


     有一个属性需要注意,就是mappedBy,这个属性只是在关系的被维护端出现,这个属性指定了使用关系维护端的哪个属性来进行维护外键(外键指的是针对表而言,在实体对象中的话指的是某一个属性)

    并且只有关系的维护端负责更新外键的记录,关系的被维护端是没有权利更新外键记录的



1.双向关联之一对一 

这里介绍个人与身份证两个实体

   a.新建PersonToIDCard工程 将相关的jar包引入 编写配置文件 前一篇博客已有提到 这里就不说了 

       配置文件persistence.xml如下

   

<persistence xmlns="http://java.sun.com/xml/ns/persistence"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
        version="2.0">
    <persistence-unit name="under">
        <properties>
        <property name="hibernate.connection.driver_class" value="oracle.jdbc.driver.OracleDriver"/>
        <property name="hibernate.connection.username" value="under_test" />
         <property name="hibernate.connection.password" value="under_test" />
         <property name="hibernate.connection.url" value="jdbc:oracle:thin:@localhost:1521:ganew" />
         <property name="hibernate.hbm2ddl.auto" value="update" />
         <property name="hibernate.show_sql" value="true" />
        <property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect" />
        </properties>
    </persistence-unit>
</persistence>

直接看Person与IDCard两个实体内容

   Person.java

package com.undergrowth;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.Table;

/*
 * 步骤
 * 1.一对一的相互关联 各自实体中拥有对方
 * 2.设置关系维护端与被维护端 指定级联的关系
 * 3.指明外键
 * 4.添加数据
 */

@Entity
@Table(name="person_info")
public class Person {
	@Id @GeneratedValue 
	private Integer id;
	@Column(length=10,nullable=false)
	private String name;
	@Column(nullable=false)
	private Integer age;
	//all表示当person进行增删改查的时候 级联的增删改查idcard
	//optional为false表示外键不能为空
	@OneToOne(cascade=CascadeType.ALL,optional=false)
	//JoinColumn指明idcard_id作为外键 来维护两个表的关系
	@JoinColumn(name="idcard_id")
	private IDCard idCard;
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
	
	public Person(){} //用于给反射机制使用
	public IDCard getIdCard() {
		return idCard;
	}
	public void setIdCard(IDCard idCard) {
		this.idCard = idCard;
	}
	public Person(String name, Integer age, IDCard idCard) {
		super();
		this.name = name;
		this.age = age;
		this.idCard = idCard;
	}
}

身份证代码:  IDCard.java

package com.undergrowth;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Table;


@Entity
@Table(name="idcard_info")
public class IDCard {
	@Id @GeneratedValue
	private Integer id;
	@Column(length=18,nullable=false)
	private String cardNum;
	@Column(length=20,nullable=false)
	private String issuedBy;
	//mappedBy指定使用person对象的idCard这个属性来进行维护表间关系 并指明自己是关系的被维护端
	@OneToOne(mappedBy="idCard")
	private Person person;
	
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getCardNum() {
		return cardNum;
	}
	public void setCardNum(String cardNum) {
		this.cardNum = cardNum;
	}
	public String getIssuedBy() {
		return issuedBy;
	}
	public void setIssuedBy(String issuedBy) {
		this.issuedBy = issuedBy;
	}
	public IDCard(){} //用于给反射机制使用
	public IDCard(String cardNum, String issuedBy) {
		this.cardNum = cardNum;
		this.issuedBy = issuedBy;
	}
	public Person getPerson() {
		return person;
	}
	public void setPerson(Person person) {
		this.person = person;
	}
	
}

   测试单元代码:   JunitTest.java

package com.junit;

import static org.junit.Assert.*;

import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

import org.junit.Test;

public class JunitTest {

	@Test
	public void test() {
		//使用<persistence-unit name="under"> 的under来创建实体管理器工厂
		EntityManagerFactory factory=Persistence.createEntityManagerFactory("under");
		factory.close();
	}

}

  test函数中的两行代码用于测试环境是否搭建成功 并且表的结构 也是在这里创建的的 如果运行test没有错误 在oracle中 两个表的结构如下:



   修改test函数 实现保存

package com.junit;

import static org.junit.Assert.*;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

import org.junit.Test;

import com.undergrowth.IDCard;
import com.undergrowth.Person;

public class JunitTest {

	@Test
	public void test() {
		//使用<persistence-unit name="under"> 的under来创建实体管理器工厂
		EntityManagerFactory factory=Persistence.createEntityManagerFactory("under");
		EntityManager manager=factory.createEntityManager();
		manager.getTransaction().begin();
		IDCard idCard=new IDCard("1234567890", "中国云南");
		//将关系被维护端的数据传递给关系维护端的数据 用于外键的更新
		Person person=new Person("under", 20, idCard);
		//因为级联关系设置了级联保存 所以这里保存person 同时也会保存idCard
		manager.persist(person);
		manager.getTransaction().commit();
		manager.close();
		factory.close();
	}

}

运行test函数的效果

  控制台输出:

Hibernate: select hibernate_sequence.nextval from dual
Hibernate: select hibernate_sequence.nextval from dual
Hibernate: insert into idcard_info (cardNum, issuedBy, id) values (?, ?, ?)
Hibernate: insert into person_info (age, idcard_id, name, id) values (?, ?, ?, ?)


oracle中效果



至于更新、删除、查询的情况类似了



2.双向关联之一对多

    这里介绍学生与成绩

先看学生 Student.java

package com.undergrowth;

import java.util.Date;
import java.util.HashSet;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.OneToMany;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

/*
 * 实现步骤
 * 1.建立相关关联 一对多 一的一方拥有对方的集合 多的一方拥有对方的一个
 * 2.指明多的一方为关系的维护端(因为逻辑关系) 指明级联关系
 * 3.指明外键
 * 4.添加数据(将关系被维护端的数据添加到关系维护端,用于更新外键)
 */

@Entity
public class Student {
	@Id @GeneratedValue
	private Integer id;
	@Column(length=15,nullable=false)
	private String name;
	@Temporal(TemporalType.DATE) @Column(nullable=false)
	private Date birthday;
	@Lob @Column(nullable=false)
	private String descInfo;
	//指定一对多的关系 指明学生对象为关系的被维护端 使用grade对象中的student属性进行维护
	//并且级联所有的更新操作
	@OneToMany(mappedBy="student",cascade=CascadeType.ALL)
	private Set<Grade> gardes=new HashSet<Grade>();
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Date getBirthday() {
		return birthday;
	}
	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}
	public String getDescInfo() {
		return descInfo;
	}
	public void setDescInfo(String descInfo) {
		this.descInfo = descInfo;
	}
	public Set<Grade> getGardes() {
		return gardes;
	}
	public void setGardes(Set<Grade> gardes) {
		this.gardes = gardes;
	}
	public Student(){} //给反射机制使用
	public Student(String name, Date birthday, String descInfo) {
		super();
		this.name = name;
		this.birthday = birthday;
		this.descInfo = descInfo;
	}
	public void addGrades(Grade grade)
	{
		//将关系被维护端的数据传递给关系维护端  在表的级别体现为给外键赋值
		grade.setStudent(this);
		this.gardes.add(grade);
	}
}

成绩 Grade.java

package com.undergrowth;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;

@Entity
public class Grade {
	@Id @GeneratedValue
	private Integer id;
	@Column(nullable=false)
	private Float grade;
	@Column(length=20,nullable=false)
	private String courseName;
	//optional为false表示 一旦有成绩了 这个成绩必然属于某个学生的
	@ManyToOne(cascade=CascadeType.REFRESH,optional=false)
	//设置外键为student_id
	@JoinColumn(name="student_id")
	private Student student;
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public Float getGrade() {
		return grade;
	}
	public void setGrade(Float grade) {
		this.grade = grade;
	}
	public String getCourseName() {
		return courseName;
	}
	public void setCourseName(String courseName) {
		this.courseName = courseName;
	}
	public Student getStudent() {
		return student;
	}
	public void setStudent(Student student) {
		this.student = student;
	}
	
	public Grade(){}
	public Grade(Float grade, String courseName) {
	
		this.grade = grade;
		this.courseName = courseName;
	}
	
}

单元测试代码: JunitTest.java

package com.junit;

import static org.junit.Assert.*;

import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

import org.junit.Test;

public class JunitTest {

	@Test
	public void test() {
		EntityManagerFactory factory=Persistence.createEntityManagerFactory("under");
		factory.close();
	}

}

  运行test函数 oracle效果



    修改test函数

package com.junit;

import static org.junit.Assert.*;

import java.text.ParseException;
import java.text.SimpleDateFormat;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

import org.junit.Test;

import com.undergrowth.Grade;
import com.undergrowth.Student;

public class JunitTest {

	@Test
	public void test() throws ParseException {
		EntityManagerFactory factory=Persistence.createEntityManagerFactory("under");
		EntityManager manager=factory.createEntityManager();
		manager.getTransaction().begin();
		Grade grade1=new Grade(98f, "高数");
		Grade grade2=new Grade(88f, "大语");
		Student student=new Student("under", new SimpleDateFormat("yyyy-MM-dd").parse("1999-9-9"), "奋斗,读书中...");
		//学生中添加成绩 1:m  并且将学生的主键传递给成绩 实现外键的更新
		student.addGrades(grade1);
		student.addGrades(grade2);
		//保存学生的信息 因为级联关系中有级联保存 所以会同时保存grade1和grade2
		manager.persist(student);
		manager.getTransaction().commit();
		manager.close();
		factory.close();
	}

}

控制台输出:

Hibernate: select hibernate_sequence.nextval from dual
Hibernate: select hibernate_sequence.nextval from dual
Hibernate: select hibernate_sequence.nextval from dual
Hibernate: insert into Student (birthday, name, id, descInfo) values (?, ?, ?, ?)
Hibernate: insert into Grade (courseName, grade, student_id, id) values (?, ?, ?, ?)
Hibernate: insert into Grade (courseName, grade, student_id, id) values (?, ?, ?, ?)

oracle效果:






3.双向关联之多对多

   这里介绍商品与顾客的关系

对于一对一和一对多 两者之间都是通过外键建立的关联  而对于多对多而言 这里要借助关联表来实现 意思就是说关联表用来连接两个多对多的表

商品 Commodity.java

package com.undergrowth;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;

/*
 * 1.建立相互关系 各自拥有对方的集合
 * 2.指定关系维护端与被关系维护端 指定级联的关系
 * 3.指定关联表 关联表的外键
 * 4.向关系维护端添加数据 相当于向关联表中添加数据 向关系维护端删除数据 相当于向关联表中删除数据
 */

@Entity
public class Commodity {
	@Id @GeneratedValue
	private Integer id;
	@Column(length=20,nullable=false)
	private String commName;
	@Column(nullable=false)
	private Float commPrice;
	@Column(length=20,nullable=false)
	private String commVender;
	@ManyToMany
	//指定多对多的关联表为comm_consu 表中分别由两个外键 指向被维护端的外建为consu_id 维护端的外键为comm_id
	@JoinTable(name="comm_consu",inverseJoinColumns=@JoinColumn(name="consu_id"),joinColumns=@JoinColumn(name="comm_id"))
	private Set<Consumer> consumers=new HashSet<Consumer>();
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getCommName() {
		return commName;
	}
	public void setCommName(String commName) {
		this.commName = commName;
	}
	public Float getCommPrice() {
		return commPrice;
	}
	public void setCommPrice(Float commPrice) {
		this.commPrice = commPrice;
	}
	public String getCommVender() {
		return commVender;
	}
	public void setCommVender(String commVender) {
		this.commVender = commVender;
	}
	public Set<Consumer> getConsumers() {
		return consumers;
	}
	public void setConsumers(Set<Consumer> consumers) {
		this.consumers = consumers;
	}
	public Commodity(){}
	public Commodity(String commName, Float commPrice, String commVender) {
		this.commName = commName;
		this.commPrice = commPrice;
		this.commVender = commVender;
	}
	
	public void addConsumer(Consumer consumer)
	{
		//向集合中添加数据 相当于向关联表中插入数据
		this.consumers.add(consumer); 
	}
	
	public void removeConsumer(Consumer consumer)
	{
		//因为hashset判断两个对象是否相等 使用的是equals方法 并且hashcode也要一样 才相等
		//所以想要id标示一个consumer对象 必须要使用id重写equals与hashcode方法
		if(this.consumers.contains(consumer))
		this.consumers.remove(consumer);
	}
	
}

顾客 Consumer.java

package com.undergrowth;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToMany;

@Entity
public class Consumer {
	@Id @GeneratedValue
	private Integer id;
	@Column(length=20,nullable=false)
	private String name;
	@Column(nullable=false)
	private Integer age;
	@ManyToMany(mappedBy="consumers")
	private Set<Commodity> commodities=new HashSet<Commodity>();
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
	public Set<Commodity> getCommodities() {
		return commodities;
	}
	public void setCommodities(Set<Commodity> commodities) {
		this.commodities = commodities;
	}
	public Consumer(){}
	public Consumer(String name, Integer age) {
		super();
		this.name = name;
		this.age = age;
	}
	@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;
		Consumer other = (Consumer) obj;
		if (id == null) {
			if (other.id != null)
				return false;
		} else if (!id.equals(other.id))
			return false;
		return true;
	}
	
}

测试单元 JunitTest.java

package com.junit;

import static org.junit.Assert.*;

import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

import org.junit.Test;

public class JunitTest {

	@Test
	public void test() {
		EntityManagerFactory factory=Persistence.createEntityManagerFactory("under");
		
		factory.close();
	}

}

  运行test 创建表结构 如下:



修改test函数 实现多对多的映射关系

  

package com.junit;

import static org.junit.Assert.*;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

import org.junit.Test;

import com.sun.org.apache.bcel.internal.generic.NEW;
import com.undergrowth.Commodity;
import com.undergrowth.Consumer;

public class JunitTest {

	@Test
	public void test() {
		EntityManagerFactory factory=Persistence.createEntityManagerFactory("under");
		EntityManager manager=factory.createEntityManager();
		manager.getTransaction().begin();
		manager.persist(new Commodity("lenovo笔记本", 5000f, "联想集团"));
		manager.persist(new Consumer("under", 20));
		manager.getTransaction().commit();
		manager.close();
		factory.close();
	}

}

  以上修改只是向commodity和consumer中添加了记录 但是两者之间的关系 还是没有建立   因此我们还需要手动的建立两者间的关系

oracle效果如下:

  


建立两个表之间的多对多的关系 添加建立关系函数 如下:

package com.junit;

import static org.junit.Assert.*;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

import org.junit.Test;

import com.sun.org.apache.bcel.internal.generic.NEW;
import com.undergrowth.Commodity;
import com.undergrowth.Consumer;

public class JunitTest {

	@Test
	public void test() {
		EntityManagerFactory factory=Persistence.createEntityManagerFactory("under");
		EntityManager manager=factory.createEntityManager();
		manager.getTransaction().begin();
		Commodity cmoCommodity1=new Commodity("lenovo笔记本", 5000f, "联想集团");
		Commodity cmoCommodity2=new Commodity("hp笔记本", 4500f, "hp集团");
		Consumer consumer1=new Consumer("under", 20);
		Consumer consumer2=new Consumer("刘德华", 25);
		manager.persist(cmoCommodity1);
		manager.persist(cmoCommodity2);
		manager.persist(consumer1);
		manager.persist(consumer2);
		buildCC(cmoCommodity1,consumer1);
		buildCC(cmoCommodity1,consumer2);
		buildCC(cmoCommodity2,consumer2);
		manager.getTransaction().commit();
		manager.close();
		factory.close();
	}
	//建立表间关系 实质上是在向关联表中添加记录
	
	public void buildCC(Commodity cmoCommodity,Consumer consumer)
	{
		cmoCommodity.addConsumer(consumer);
	}

}

    上面即是建立了多对多的关系 一个顾客可以买多种商品 一种商品也可以被多个可以购买

控制台输出:

Hibernate: select hibernate_sequence.nextval from dual
Hibernate: select hibernate_sequence.nextval from dual
Hibernate: select hibernate_sequence.nextval from dual
Hibernate: select hibernate_sequence.nextval from dual
Hibernate: insert into Commodity (commName, commPrice, commVender, id) values (?, ?, ?, ?)
Hibernate: insert into Commodity (commName, commPrice, commVender, id) values (?, ?, ?, ?)
Hibernate: insert into Consumer (age, name, id) values (?, ?, ?)
Hibernate: insert into Consumer (age, name, id) values (?, ?, ?)
Hibernate: insert into comm_consu (comm_id, consu_id) values (?, ?)
Hibernate: insert into comm_consu (comm_id, consu_id) values (?, ?)
Hibernate: insert into comm_consu (comm_id, consu_id) values (?, ?)

oracle效果:







  以上即是jpa中对象之间的三种关系实现 

原文地址:https://www.cnblogs.com/liangxinzhi/p/4275594.html