本章主要是描述几种经典映射关系,顺带比较Hibernate4.x和Hibernate5.x之间的区别。

一、建立测试工程目录

有关实体类之间的相互映射关系,Hibernate官方文档其实描述的非常详细,这里只提供几种常见映射。(推荐4.3.11版本的 hibernate-release-4.3.11.Final\documentation\manual)

二、编写映射关系

(1)one2one单表内嵌映射:

package model.family;

import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity
public class Husband {
    private int id;
    private String husbandName;
    private Wife wife;

    @Id
    @GeneratedValue
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getHusbandName() {
        return husbandName;
    }

    public void setHusbandName(String husbandName) {
        this.husbandName = husbandName;
    }

    // 两个实体对象共用一张数据表,提高查询速度
    @Embedded
    public Wife getWife() {
        return wife;
    }

    public void setWife(Wife wife) {
        this.wife = wife;
    }

}

Husband.java

package model.family;

//不用添加任何注解,持久化过程通过主表完成
public class Wife {
    private String wifeName;

    public String getWifeName() {
        return wifeName;
    }

    public void setWifeName(String wifeName) {
        this.wifeName = wifeName;
    }
}

Wife.java

(2)one2one外键映射:

package model.userinfo;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Transient;

@Entity
public class User {
    private int id;
    private String username;
    private String password;
    private String confirm;
    private Information info;

    @Id
    @GeneratedValue
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    /*
     * 延迟加载,级联操作。
     * 删除开启了级联的一方,被级联的一方也会被删除
     * 注意:如果session的操作是通过hibernate控制,延迟加载不会出问题。如果是通过手工开启实物,操作不当延迟加载可能抛出懒加载异常
     */
    @OneToOne(fetch = FetchType.LAZY, mappedBy = "user", cascade = CascadeType.ALL)
    public Information getInfo() {
        return info;
    }

    public void setInfo(Information info) {
        this.info = info;
    }

    // 本字段不参与持久化过程
    @Transient
    public String getConfirm() {
        return confirm;
    }

    public void setConfirm(String confirm) {
        this.confirm = confirm;
    }
}

User.java

package model.userinfo;

import java.util.Date;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

//注解也可以直接配置在字段上,但是不推荐。据说原因是可能破坏oop封装。但是我觉得有时这样配置可以让代码显得更加整洁,特别是在Spring中。
@Entity
public class Information {
    @Id
    @GeneratedValue
    private int id;
    @OneToOne
    private User user;
    @Temporal(TemporalType.DATE)
    private Date resgisterDate;
    private String address;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public Date getResgisterDate() {
        return resgisterDate;
    }

    public void setResgisterDate(Date resgisterDate) {
        this.resgisterDate = resgisterDate;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

}

Information.java

(3)many2many多表映射:

场景描述:学校里有多个老师,每个老师教授多个学生,每个学生每一门课程会有一个得分。

 package model.school;

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

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

@Entity
public class Teacher {
    private int id;
    private String tchName;
    private Set<Student> students = new HashSet<Student>();

    @Id
    @GeneratedValue
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getTchName() {
        return tchName;
    }

    public void setTchName(String tchName) {
        this.tchName = tchName;
    }

    //老师和学生的对应表由学生一方负责维护
    @ManyToMany(mappedBy = "teachers")
    public Set<Student> getStudents() {
        return students;
    }

    public void setStudents(Set<Student> students) {
        this.students = students;
    }

}

Teacher.java

package model.school;

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

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

@Entity
public class Student {
    private int id;
    private String stuName;
    private Set<Teacher> teachers = new HashSet<Teacher>();
    private Set<Score> scores = new HashSet<Score>();

    @Id
    @GeneratedValue
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getStuName() {
        return stuName;
    }

    public void setStuName(String stuName) {
        this.stuName = stuName;
    }

    /*
     * many2many必须使用中间表,配置中间表的表明和列名
     */
    @ManyToMany
    @JoinTable(name = "student_teacher", joinColumns = { @JoinColumn(name = "studentId") }, inverseJoinColumns = {
            @JoinColumn(name = "teacherId") })
    public Set<Teacher> getTeachers() {
        return teachers;
    }

    public void setTeachers(Set<Teacher> teachers) {
        this.teachers = teachers;
    }

    // 学生同分数之间的关系同样交给多的一方负责维护
    @OneToMany(mappedBy = "student")
    public Set<Score> getScores() {
        return scores;
    }

    public void setScores(Set<Score> scores) {
        this.scores = scores;
    }

}

Student.java

package model.school;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;

@Entity
public class Score {
    private int id;
    private int courseScore;
    private Teacher teacher;
    private Student student;

    @Id
    @GeneratedValue
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getCourseScore() {
        return courseScore;
    }

    public void setCourseScore(int courseScore) {
        this.courseScore = courseScore;
    }

    @ManyToOne
    public Teacher getTeacher() {
        return teacher;
    }

    public void setTeacher(Teacher teacher) {
        this.teacher = teacher;
    }

    @ManyToOne
    public Student getStudent() {
        return student;
    }

    public void setStudent(Student student) {
        this.student = student;
    }

}

Score.java

按照以上的映射关系生成数据表以后会注意到,其实老师和学生之间的关系表纯粹多余,分数表已经维护了双方的关系。重新优化他们之间的映射关系:

package model.school;

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

@Entity
public class Teacher {
    private int id;
    private String tchName;

    @Id
    @GeneratedValue
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getTchName() {
        return tchName;
    }

    public void setTchName(String tchName) {
        this.tchName = tchName;
    }

}

Teacher.java

package model.school;

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

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;

@Entity
public class Student {
    private int id;
    private String stuName;
    private Set<Score> scores = new HashSet<Score>();

    @Id
    @GeneratedValue
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getStuName() {
        return stuName;
    }

    public void setStuName(String stuName) {
        this.stuName = stuName;
    }

    @OneToMany(mappedBy = "student")
    public Set<Score> getScores() {
        return scores;
    }

    public void setScores(Set<Score> scores) {
        this.scores = scores;
    }

}

Student.java

package model.school;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;

@Entity
public class Score {
    private int id;
    private int courseScore;
    private Teacher teacher;
    private Student student;

    @Id
    @GeneratedValue
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getCourseScore() {
        return courseScore;
    }

    public void setCourseScore(int courseScore) {
        this.courseScore = courseScore;
    }

    @ManyToOne
    public Teacher getTeacher() {
        return teacher;
    }

    public void setTeacher(Teacher teacher) {
        this.teacher = teacher;
    }

    @ManyToOne
    public Student getStudent() {
        return student;
    }

    public void setStudent(Student student) {
        this.student = student;
    }

}

Score.java

由此可见,即使是一个相对复杂的映射关系也可以通过优化得到一个相对简单的数据模型。

(4)many2one和one2many单表树形映射:

场景描述:地图,一个国家包含多个省份,每个省份又包含多个城市...

package model.tree;

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.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity
@Table(name = "_tree")
public class Tree {
    private int id;
    private String name;
    private Tree parent;
    private Set<Tree> children = new HashSet<Tree>();

    @Id
    @GeneratedValue
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @Column(name = "t_name", unique = true)
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @ManyToOne
    public Tree getParent() {
        return parent;
    }

    public void setParent(Tree parent) {
        this.parent = parent;
    }

    //删除根节点,与它相关的所有子节点全部删除
    @OneToMany(mappedBy = "parent", cascade = CascadeType.ALL)
    public Set<Tree> getChildren() {
        return children;
    }

    public void setChildren(Set<Tree> children) {
        this.children = children;
    }
}

Tree.java

注意:以上4种映射关系在4.3.11版本中正常。但在5.0.6版本中id字段被系统强制指定为了@GeneratedValue(strategy=GenerationType.TABLE)的方式。我曾经尝试手工指定生成策略为auto或者identity均无效。如果是通过xml的方式配置是正常的,目前我还不清楚是什么原因导致的上述异常。这个问题造成了下面的映射关系目前只能在4.x版本中正常使用:

(5)one2one主键映射

package model.personaddr;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.PrimaryKeyJoinColumn;

@Entity
public class Person {
    private int id;
    private String name;
    private Address address;

    @Id
    @GeneratedValue
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    // 两张表通过主键关联
    @OneToOne(optional = true)
    @PrimaryKeyJoinColumn
    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }
}

Person.java

package model.personaddr;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToOne;

@Entity
public class Address {
    private int id;
    private String local;
    private Person person;

    @Id
    @GeneratedValue
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getLocal() {
        return local;
    }

    public void setLocal(String local) {
        this.local = local;
    }

    @OneToOne(mappedBy = "address")
    public Person getPerson() {
        return person;
    }

    public void setPerson(Person person) {
        this.person = person;
    }

}

Address.java

ps:好在主键映射在实际使用中并不常见。


最后按照惯例,提供整个项目的完整目录结构和IDE版本信息

Hibernate 基础配置及常用功能(二)的更多相关文章

  1. Hibernate 基础配置及常用功能(三)

    本章重点讲述Hibernate对象的三种状态以及如何配置二级缓存 有关Hibernate的三种状态如何相互转换网上都能查到,官方文档描述的也比较详细.这里主要是针对几个重点方法做代码演示. 一.状态转 ...

  2. Hibernate 基础配置及常用功能(一)

    本来是想等全部框架测试完以后再统一发布的,但是随着测试的一点点增加感觉把需要叙述的东西放在一起终将会是一场灾难.所以还是打算分成几章来描述,其中还包括一些有待解决的问题.短期很难腾出时间来仔细阅读Hi ...

  3. 从零开始学习jQuery (十) jQueryUI常用功能实战

    一.摘要 本系列文章将带您进入jQuery的精彩世界, 其中有很多作者具体的使用经验和解决方案,  即使你会使用jQuery也能在阅读中发现些许秘籍. 本文是实战篇. 使用jQueryUI完成制作网站 ...

  4. logback 常用配置详解(二) &lt;appender&gt;

    logback 常用配置详解(二) <appender> <appender>: <appender>是<configuration>的子节点,是负责写 ...

  5. Keil的使用方法 - 常用功能(二)

    Ⅰ.概述 上一篇文章是总结关于Keil使用方法-常用功能(一),关于(文件和编译)工具栏每一个按钮的功能描述和快捷键的使用. 我将每一篇Keil使用方法的文章都汇总在一起,回顾前面的总结请点击下面的链 ...

  6. 【转】logback logback.xml常用配置详解(二)&lt;appender&gt;

    原创文章,转载请指明出处:http://aub.iteye.com/blog/1101260, 尊重他人即尊重自己 详细整理了logback常用配置, 不是官网手册的翻译版,而是使用总结,旨在更快更透 ...

  7. Hibernate基础学习(二)&mdash;Hibernate相关API介绍

    一.Hibernate的核心接口      所有的Hibernate应用中都会访问Hibernate的5个核心接口.      (1)Configuration接口: 配置Hibernate,启动Hi ...

  8. 新建structs2 web应用及structs.xml常用基础配置

    建立一个structs2 web应用程序 1. 创建一个基本的web应用程序 2. 添加structs2的jar文件到Class Path 将structs2的最小jar包拷到WEB-INF/lib目 ...

  9. Struts+Hibernate+Spring实现用户登录功能

    通过登录案例实现三大框架之间的整合,登录功能是任何系统和软件必不可少的一个模块,然而通过这个模块来认识这些复杂的框架技术,理解数据流向和整个设计思路是相当容易的.只有在掌握了这些小模块的应用后,才能轻 ...

随机推荐

  1. Atitit. 查找linux 项目源码位置

    Atitit. 查找linux 项目源码位置 1. netstat   -anp |grep 801 1.1. 1.3 启动关闭nginx3 1.2. 找到nginx配置文件4 1.3. ./etc/ ...

  2. IP多媒体子系统(IP Multimedia Subsystem,IMS)

      目录 1 什么是IP多媒体子系统[1] 2 IMS产生的背景[2] 3 IMS的特点分析[3] 4 IMS中的功能实体[3] 5 IMS中的接口和协议[3] 6 参考文献 [编辑] 什么是IP多媒 ...

  3. xloader

    [1],先看一下整个系统的结构(软件是灵魂,硬件是驱体,再强大的灵魂力若没有躯体终将是游魂野鬼,再强壮的驱体若没有灵魂终将是植物人) 结构 作用 备注 硬件 一切软件的载体   xloader 引导u ...

  4. vs文件属性(生成操作)各选项功能(发布Web项目时使用)

    转自:http://www.cnblogs.com/paulhe/p/4490583.html 右击项目里的文件,选择属性(F4)会有[生成操作]的选项. 它提供了14项选择,如图: 在这说一下常用的 ...

  5. http的500,502,504错误

    500 500的错误通常是由于服务器上代码出错或者是抛出了异常 解决方法:查看一下对应的代码是不是有问题. 502 502即 Bad Gateway网关(这里的网关是指CGI,即通用网关接口,从名字就 ...

  6. Android adb push 和 pull操作

    由于安卓真机本地调试时,每次启动并生成apk然后安装到设备比较费时,而很多情况是仅仅修改了hot 脚本文件(cocos2dx + lua). 所以,使用热更机制把修改后的lua文件push到热更目录( ...

  7. 已Access为支持,书写一个C#写入的记录的方案

      /// <summary> /// 读取Excel文档 /// </summary> /// <param name="Path">文件名称 ...

  8. JSP 动作元素

    JSP动作元素 1.  动作元素分类 用来动态的包含文件.网页跳转及使用JavaBean组件等. 语法:<jsp:XXX />或者<jsp:XXX></jsp:XXX&g ...

  9. iPhone 屏幕上的 Home 键在哪里?(已解决)

    「问」:iPhone屏幕上的Home键如何开启? 「答」:在[设置]-[通用]-[辅助功能]-[AssistiveTouch],打开即可.不需要下载什么App. [Settings] - [Gener ...

  10. linux传送文件至服务器

    scp安全文件拷贝(基于ssh的登陆)     1.你想把本地/home下的文件linux.tar.gz传送至远端服务器10.108.125.30,远端服务器的账号名为name,保存至服务器/home ...