zoukankan      html  css  js  c++  java
  • 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中对象之间的三种关系实现 

  • 相关阅读:
    移动端屏幕适配解决方案
    ES6学习笔记(1)——模块化
    弹性盒布局学习总结
    阮一峰之webpack-demos(译)
    阮一峰的Git分支管理策略之学习总结
    移动端测试之服务器搭建
    webApp 移动Touch框架
    Javascript 严格模式详解
    caller和callee的区别
    avalon 中require.config源码分析
  • 原文地址:https://www.cnblogs.com/liangxinzhi/p/4275594.html
Copyright © 2011-2022 走看看