JPA之OneToMany和ManyToOne例子

2014-07-02 summer 更多博文 » 博客 » GitHub »

jpa

原文链接 http://fee.im/2014/07/JPA-One-To-Many/
注:以下为加速网络访问所做的原文缓存,经过重新格式化,可能存在格式方面的问题,或偶有遗漏信息,请以原文为准。


前期准备

开发环境的搭建工作完全可以参考jpa小例子。 该程序的例子使用班级和学生进行,班级和学生的关系是一对多的关系,反过来学生和班级的关系是 多对一的关系。所以从这个例子中我们就可以学习到这两个关系的处理。

基本知识

在OneToMany和ManyToOne使用过程中,需要我们明确两个概念:关系维护端和关系被维护端。关系维护端负责更新关系的外键等操作。在程序中被标记mappBy的表示关系被维护端,只有关系维护端有权更新外键。 数据加载方式可以根据名字进行辨别,OneToMany默认的加载方式是懒加载,从设置的关系中(OneToMany和ManyToOne)最后一个单词是Many,那么该加载默认为懒加载。 在所有的关系中OneToMany、ManyToOne、ManyToMany,以many结尾的默认加载方式都是懒加载。

代码

下面是classes班级的类

package com.nova.bean;

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.OneToMany;

@Entity
public class Classes {
    @Id
    @GeneratedValue
    private Integer id;
    @Column(length = 100, nullable = false)
    private String name;

    //mappedBy标记为关系被维护端,所以外键关系由student端维护。
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "classes")
    private Set<Student> set = new HashSet<Student>();

    public Classes() {

    }

    public Classes(String name) {
        this.name = name;
    }

    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 Set<Student> getSet() {
        return set;
    }

    public void setSet(Set<Student> set) {
        this.set = set;
    }
}

下面是学生类

package com.nova.bean;

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

@Entity
public class Student {
    @Id
    @GeneratedValue
    private Integer id;
    @Column(length = 100, nullable = false)
    private String name;
    @Column(length = 3)
    private Integer age;
    @Column(length = 5)
    private Gender gender = Gender.MAN;

    @ManyToOne(cascade = { CascadeType.MERGE, CascadeType.REFRESH }, optional = true)
    @JoinColumn(name = "classId") //这里设置JoinColum设置了外键的名字
    private Classes classes;

    public Student() {

    }

    public Student(String name, Integer age, Gender gender) {
        this.name = name;
        this.age = age;
        this.gender = gender;
    }

    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 Gender getGender() {
        return gender;
    }

    public void setGender(Gender gender) {
        this.gender = gender;
    }

    public Classes getClasses() {
        return classes;
    }

    public void setClasses(Classes classes) {
        this.classes = classes;
    }
}

下面是单元测试

package com.nova.bean;

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

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

import org.junit.Test;

public class OneToManyTest {

    @Test
    public void init() {
        // 可以验证生成表是否正确
        EntityManagerFactory factory = Persistence
                .createEntityManagerFactory("myJpa");
        factory.close();
    }

    @Test
    public void create() {
        EntityManagerFactory emf = Persistence
                .createEntityManagerFactory("myJpa");
        EntityManager em = emf.createEntityManager();
        em.getTransaction().begin();

        Classes c = new Classes("一年级三班");
        Set<Student> set = new HashSet<Student>();

        Student s1 = new Student("小张", 6, Gender.MAN);
        s1.setClasses(c);
        set.add(s1);
        Student s2 = new Student("萧文", 5, Gender.WOMAN);
        s2.setClasses(c);
        set.add(s2);
        c.setSet(set);

        em.persist(c);

        em.getTransaction().commit();
        em.close();
        emf.close();
    }

    @Test
    public void read() {
        EntityManagerFactory emf = Persistence
                .createEntityManagerFactory("myJpa");
        EntityManager em = emf.createEntityManager();
        em.getTransaction().begin();

        Classes c = em.find(Classes.class, 1);
        System.out.println(c.getName());
        for (Student s : c.getSet()) {
            System.out.println(s.getName());
        }

        em.getTransaction().commit();
        em.close();
        emf.close();
    }

    @Test
    public void update() {
        EntityManagerFactory emf = Persistence
                .createEntityManagerFactory("myJpa");
        EntityManager em = emf.createEntityManager();
        em.getTransaction().begin();

        Classes c = em.find(Classes.class, 1);
        Student s = em.find(Student.class, 2);
        c.setName("三年级");
        s.setName("小张");
        s.setClasses(c);

        em.merge(c);
        em.getTransaction().commit();
        em.close();
        emf.close();
    }

    /**
     * 删除班级和学生的所有记录
     * 
     * 删除班级的时候,会自动把关联学生的记录删除
     */
    @Test
    public void delete() {
        EntityManagerFactory emf = Persistence
                .createEntityManagerFactory("myJpa");
        EntityManager em = emf.createEntityManager();
        em.getTransaction().begin();

        Classes c = em.find(Classes.class, 1);
        em.remove(c);

        em.getTransaction().commit();
        em.close();
        emf.close();
    }

    /**
     * 删除学生的记录
     * 
     * 删除学生时不会影响班级的数据
     */
    @Test
    public void delete1() {
        EntityManagerFactory emf = Persistence
                .createEntityManagerFactory("myJpa");
        EntityManager em = emf.createEntityManager();
        em.getTransaction().begin();

        Student s = em.find(Student.class, 4);
        em.remove(s);

        em.getTransaction().commit();
        em.close();
        emf.close();
    }

}

总结

在OneToMany和ManyToOne中主要弄清楚什么是关系维护端,什么是关系被维护端。mappBy标记的一定是关系被维护端,关系维护端负责外键的更新。