本文将接着上文,讲解hibernate4的集合映射的注解和关联关系映射的注解。本文包括两个部分:
一、集合映射的注解
当持久化中有一个属性是集合(Set、List、Map),就要用到集合映射。集合属性会单独生成一张表。定义集合属性时面向接口,并且集合属性需要程序员自己初始化(例如:private List
list = new ArrayList ();)。
集合属性都要用到的注解:
- @ElementCollection(fetch="该属性的加载策略",targetClass="集合中元素的类型")。
fetch=FetchType.EAGER: 立即加载
fetch=FetchType.LAZY: 延迟加载- @CollectionTable(name="表名") : 指定集合生成表的相关信息。
1.1 List集合映射(有序集合): @OrderColumn() 指定排序列
注意:List集合生成表的主键列:(外键列 + 排序列)
1.1.1 List
: 集合中元素是标量类型 8个基本类型、包装类、String。 例如:Employee类
package edu.scut.e_CollectionMapping_List; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import javax.persistence.*; @Entity @Table(name="EMP_INFO") public class Employee implements Serializable { @Id @GeneratedValue(strategy=GenerationType.AUTO) private int id; private String name; private int age; @ElementCollection(fetch=FetchType.LAZY, //加载策略,延迟加载 targetClass=String.class) //指定集合中元素的类型 @CollectionTable(name="ADD_INFO") //指定集合生成的表 @OrderColumn(name="O_ID") //指定排序列的名称 private List
address = new ArrayList (); public int getId() { return id; } public List getAddress() { return address; } public void setAddress(List address) { this.address = address; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
生成两张表:emp_info表
add_info表
1.1.2 List : 集合中元素是复合类型。复合属性类上需要加注解:@Embeddable。
例如:Person类
package edu.scut.e_CollectionMapping_List; import java.util.ArrayList; import java.util.List; import javax.persistence.*; @Entity @Table(name="PER_INFO") public class Person { @Id @GeneratedValue(strategy=GenerationType.AUTO) private int id; private String name; @ElementCollection(fetch=FetchType.LAZY, //加载策略 targetClass=Address.class) //指定元素中集合的类型 @CollectionTable(name="PER_ADD_INFO") //指定集合生成的表 @OrderColumn(name="O_A_ID") //指定排序列的名称 private List address = new ArrayList(); 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; } public List getAddress() { return address; } public void setAddress(List address) { this.address = address; } }
Address类
package edu.scut.e_CollectionMapping_List; import javax.persistence.Embeddable; @Embeddable public class Address { private String zip; private String info; public String getZip() { return zip; } public void setZip(String zip) { this.zip = zip; } public String getInfo() { return info; } public void setInfo(String info) { this.info = info; } }
生成的两张表:per_info表
per_add_info表
1.2 Set集合映射(无序集合)
注意: Set集合生成表的主键列:(外键列 + Set集合的元素列 .. )
1.2.1· Set: 集合中元素是标量类型 8个基本类型、包装类、String。
Set集合生成表默认是没有主键列的。如果想要生成主键列,需要为Set集合添加非空约束!
例如:Employee类
package edu.scut.e_CollectionMapping_Set; import java.io.Serializable; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.persistence.*; @Entity @Table(name="EMP_INFO") public class Employee implements Serializable { @Id @GeneratedValue(strategy=GenerationType.AUTO) private int id; private String name; private int age; @ElementCollection(fetch=FetchType.LAZY, //加载策略,延迟加载 targetClass=String.class) //指定集合中元素的类型 @CollectionTable(name="ADD_INFO") //指定集合生成的表 @Column(nullable=false) //添加非空约束 private Set
address = new HashSet (); public int getId() { return id; } public Set getAddress() { return address; } public void setAddress(Set address) { this.address = address; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
1.2.2 Set : 集合中元素是复合类型。
复合属性类上需要加注解:@Embeddable
Set集合生成表默认是没有主键列的。如果想要生成主键列,需要为Set集合的元素类的属性上添加非空约束!
例如:Person类
package edu.scut.e_CollectionMapping_Set; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.persistence.*; @Entity @Table(name="PER_INFO") public class Person { @Id @GeneratedValue(strategy=GenerationType.AUTO) private int id; private String name; @ElementCollection(fetch=FetchType.LAZY, //加载策略 targetClass=Address.class) //指定元素中集合的类型 @CollectionTable(name="PER_ADD_INFO") //指定集合生成的表 private Set address = new HashSet(); 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; } public Set getAddress() { return address; } public void setAddress(Set address) { this.address = address; } }
Address类
package edu.scut.e_CollectionMapping_Set; import javax.persistence.Column; import javax.persistence.Embeddable; @Embeddable public class Address { //@Column(nullable=false) private String zip; @Column(nullable=false) private String info; public String getZip() { return zip; } public void setZip(String zip) { this.zip = zip; } public String getInfo() { return info; } public void setInfo(String info) { this.info = info; } }
1.3 Map集合映射(有Map的key): @MapKeyColumn() 指定Map的key生成的列
注意: Map集合生成表的主键列:(外键列 + Map的Key)
1.3.1 Map
: 集合中元素是标量类型 8个基本类型、包装类、String。 例如:Employee类
package edu.scut.e_CollectionMapping_Map; import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.persistence.*; @Entity @Table(name="EMP_INFO") public class Employee implements Serializable { @Id @GeneratedValue(strategy=GenerationType.AUTO) private int id; private String name; private int age; @ElementCollection(fetch=FetchType.LAZY, //加载策略,延迟加载 targetClass=String.class) //指定集合中元素的类型 @CollectionTable(name="ADD_INFO") //指定集合生成的表 @MapKeyColumn(name="M_KEY") //指定map的key生成的列 private Map
address = new HashMap (); public int getId() { return id; } public Map getAddress() { return address; } public void setAddress(Map address) { this.address = address; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } 1.3.2 Map
: 集合中元素是复合类型。
复合属性类上需要加注解:@Embeddable
例如:Person类package edu.scut.e_CollectionMapping_Map; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import javax.persistence.*; @Entity @Table(name="PER_INFO") public class Person { @Id @GeneratedValue(strategy=GenerationType.AUTO) private int id; private String name; @ElementCollection(fetch=FetchType.LAZY, //加载策略 targetClass=Address.class) //指定元素中集合的类型 @CollectionTable(name="PER_ADD_INFO") //指定集合生成的表 @MapKeyColumn(name="ADD_KEY") //指定key生成的列 private Map
address = new HashMap (); 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; } public Map getAddress() { return address; } public void Address(Map address) { this.address = address; } } Address类
package edu.scut.e_CollectionMapping_Map; import javax.persistence.Column; import javax.persistence.Embeddable; @Embeddable public class Address { //@Column(nullable=false) private String zip; @Column(nullable=false) private String info; public String getZip() { return zip; } public void setZip(String zip) { this.zip = zip; } public String getInfo() { return info; } public void setInfo(String info) { this.info = info; } }
二、关联关系映射的注解(重点)
单向关联映射和双向关联映射的最大区别就是在查询数据时,单向关联只能通过一边进行查询,而双向关联两边都可以互相查询。
2.1 单向关联映射(一边配置)
2.1.1 一对一
/** 一方*/ @OneToOne(fetch=FetchType.LAZY, cascade=CascadeType.ALL, targetEntity=Persons.class) //维护关联关系(从表) /** 生成外键列*/ @JoinColumn(name="P_ID",unique=true,referencedColumnName="id")
通过公民(Person)和身份证(IdCards)的例子来说明:
Person.java
package edu.scut.f_AssoMap_single_one2one; import javax.persistence.*; //公民(一方) @Entity @Table(name="PER_INFO") public class Persons { @Id @GeneratedValue(strategy=GenerationType.AUTO) private int id; private String name; 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; } }
IdCards.java
package edu.scut.f_AssoMap_single_one2one; import javax.persistence.*; //身份证(一方) @Entity @Table(name="IDCD_INFO") public class IdCards { @Id @GeneratedValue(strategy=GenerationType.AUTO) @Column(name="IDCD_ID") private int id; private String cardno; /** 一方*/ @OneToOne(fetch=FetchType.LAZY, cascade=CascadeType.ALL, targetEntity=Persons.class) //维护关联关系(从表) /** 生成外键列*/ @JoinColumn(name="P_ID",unique=true,referencedColumnName="id") private Persons persons; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getCardno() { return cardno; } public void setCardno(String cardno) { this.cardno = cardno; } public Persons getPersons() { return persons; } public void setPersons(Persons persons) { this.persons = persons; } }
2.1.2 一对多
/** 一方*/ @OneToMany(fetch=FetchType.LAZY, //延迟加载 targetEntity=Orders.class, //目标对象 cascade=CascadeType.ALL,//级联操作 orphanRemoval=true) //孤儿删除 @JoinColumn(name="C_ID",referencedColumnName="CUS_ID")
通过客户(Customers)和订单(Orders)的例子说明:
Customers.java
package edu.scut.f_AssoMap_single_one2n; import java.util.HashSet; import java.util.Set; import javax.persistence.*; //客户(一方) @Entity @Table(name="CUS_INFO") public class Customers { @Id @GeneratedValue(strategy=GenerationType.AUTO) @Column(name="CUS_ID") private int id; private String name; /** 一方*/ @OneToMany(fetch=FetchType.LAZY, //延迟加载 targetEntity=Orders.class, //目标对象 cascade=CascadeType.ALL,//级联操作 orphanRemoval=true) //孤儿删除 @JoinColumn(name="C_ID",referencedColumnName="CUS_ID") private Set
orders = new HashSet (); 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; } public Set getOrders() { return orders; } public void setOrders(Set orders) { this.orders = orders; } } Orders.java
package edu.scut.f_AssoMap_single_one2n; import javax.persistence.*;; import javax.persistence.Table; //订单(多方) @Entity @Table(name="ORD_INFO") public class Orders { @Id @GeneratedValue(strategy=GenerationType.AUTO) private int id; private String orderno; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getOrderno() { return orderno; } public void setOrderno(String orderno) { this.orderno = orderno; } }
2.1.3 多对一
/** 多方*/ @ManyToOne(fetch=FetchType.LAZY, cascade=CascadeType.ALL, targetEntity=Customers.class) /** 生成外键列*/ @JoinColumn(name="C_ID",referencedColumnName="CUS_ID")
通过客户(Customers)和订单(Orders)的例子说明:
Customers.java
package edu.scut.f_AssoMap_single_n2one; import java.util.HashSet; import java.util.Set; import javax.persistence.*; //客户(一方) @Entity @Table(name="CUS_INFO") public class Customers { @Id @GeneratedValue(strategy=GenerationType.AUTO) @Column(name="CUS_ID") private int id; private String name; 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; } }
Orders.java
package edu.scut.f_AssoMap_single_n2one; import javax.persistence.*; //订单(多方) @Entity @Table(name="ORD_INFO") public class Orders { @Id @GeneratedValue(strategy=GenerationType.AUTO) private int id; private String orderno; /** 多方*/ @ManyToOne(fetch=FetchType.LAZY, cascade=CascadeType.ALL, targetEntity=Customers.class) /** 生成外键列*/ @JoinColumn(name="C_ID",referencedColumnName="CUS_ID") private Customers customers; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getOrderno() { return orderno; } public void setOrderno(String orderno) { this.orderno = orderno; } public Customers getCustomers() { return customers; } public void setCustomers(Customers customers) { this.customers = customers; } }
2.1.4 多对多
/** 多方*/ @ManyToMany(fetch=FetchType.LAZY, //延迟加载 cascade=CascadeType.ALL, targetEntity=Teacher.class) //目标对象 /** 中间表*/ @JoinTable(name="TEA_STU", //指定中间表名称 joinColumns=@JoinColumn(name="S_ID",referencedColumnName="STU_ID"), //@ManyToMany中没有加mappedby的主键列 inverseJoinColumns=@JoinColumn(name="T_ID",referencedColumnName="TEA_ID")) //@ManyToMany中加mappedby的主键列
通过老师(Teachers)和学生(Students)的例子说明:
Teachers.java
package edu.scut.f_AssoMap_single_n2n; import java.util.HashSet; import java.util.Set; import javax.persistence.*; //多方 @Entity @Table(name="TEA_INFO") public class Teacher { @Id @GeneratedValue(strategy=GenerationType.AUTO) @Column(name="TEA_ID") private int id; private String name; private String dept; 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; } public String getDept() { return dept; } public void setDept(String dept) { this.dept = dept; } }
Students.java
package edu.scut.f_AssoMap_single_n2n; import java.util.HashSet; import java.util.Set; import javax.persistence.*; //多方 @Entity @Table(name="STU_INFO") public class Student { @Id @GeneratedValue(strategy=GenerationType.AUTO) @Column(name="STU_ID") private int id; private String name; private float score; /** 多方*/ @ManyToMany(fetch=FetchType.LAZY, //延迟加载 cascade=CascadeType.ALL, targetEntity=Teacher.class) //目标对象 /** 中间表*/ @JoinTable(name="TEA_STU", //指定中间表名称 joinColumns=@JoinColumn(name="S_ID",referencedColumnName="STU_ID"), //@ManyToMany中没有加mappedby的主键列 inverseJoinColumns=@JoinColumn(name="T_ID",referencedColumnName="TEA_ID")) //@ManyToMany中加mappedby的主键列 private Set
teachers = new HashSet (); 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; } public float getScore() { return score; } public void setScore(float score) { this.score = score; } public Set getTeachers() { return teachers; } public void setTeachers(Set teachers) { this.teachers = teachers; } }
2.2 双向关联映射(两边同时配置)
2.2.1 一对一
一方:
另一方:/** 一方 */ @OneToOne(fetch=FetchType.LAZY, targetEntity=IdCards.class, mappedBy="persons", //不维护关联关系(主表) cascade=CascadeType.ALL)
/** 一方*/ @OneToOne(fetch=FetchType.LAZY, targetEntity=Persons.class) //维护关联关系(从表) /** 生成外键列*/ @JoinColumn(name="P_ID",unique=true,referencedColumnName="id")
还是通过公民(Persons)和身份证(IdCards)的例子来说明:
Persons.java
IdCards.javapackage edu.scut.f_AssoMap_double_one2one; import javax.persistence.*; //公民(一方) @Entity @Table(name="PER_INFO") public class Persons { @Id @GeneratedValue(strategy=GenerationType.AUTO) private int id; private String name; /** 一方 */ @OneToOne(fetch=FetchType.LAZY, targetEntity=IdCards.class, mappedBy="persons", //不维护关联关系(主表) cascade=CascadeType.ALL) private IdCards idcards; 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; } public IdCards getIdcards() { return idcards; } public void setIdcards(IdCards idcards) { this.idcards = idcards; } }
package edu.scut.f_AssoMap_double_one2one; import javax.persistence.*; //身份证(一方) @Entity @Table(name="IDCD_INFO") public class IdCards { @Id @GeneratedValue(strategy=GenerationType.AUTO) @Column(name="IDCD_ID") private int id; private String cardno; /** 一方*/ @OneToOne(fetch=FetchType.LAZY, targetEntity=Persons.class) //维护关联关系(从表) /** 生成外键列*/ @JoinColumn(name="P_ID",unique=true,referencedColumnName="id") private Persons persons; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getCardno() { return cardno; } public void setCardno(String cardno) { this.cardno = cardno; } public Persons getPersons() { return persons; } public void setPersons(Persons persons) { this.persons = persons; } }
2.2.2 一对多
一方:
/** 一方*/ @OneToMany(fetch=FetchType.LAZY, //延迟加载 targetEntity=Orders.class, //目标对象 cascade=CascadeType.ALL, //级联操作 orphanRemoval=true, //孤儿删除 mappedBy="customers") //指定由哪边维护关系(从表维护)
多方:
/** 多方*/ @ManyToOne(fetch=FetchType.LAZY, //cascade=CascadeType.ALL, targetEntity=Customers.class) /** 生成外键列*/ @JoinColumn(name="C_ID",referencedColumnName="CUS_ID")
还是通过客户(Customers)和订单(Orders)的例子说明:
Customers.java
package edu.scut.f_AssoMap_double_one2n; import java.util.HashSet; import java.util.Set; import javax.persistence.*; //客户(一方) @Entity @Table(name="CUS_INFO") public class Customers { @Id @GeneratedValue(strategy=GenerationType.AUTO) @Column(name="CUS_ID") private int id; private String name; /** 一方*/ @OneToMany(fetch=FetchType.LAZY, //延迟加载 targetEntity=Orders.class, //目标对象 cascade=CascadeType.ALL, //级联操作 orphanRemoval=true, //孤儿删除 mappedBy="customers") //指定由哪边维护关系(从表维护) private Set
orders = new HashSet (); 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; } public Set getOrders() { return orders; } public void setOrders(Set orders) { this.orders = orders; } } Orders.java
package edu.scut.f_AssoMap_double_one2n; import javax.persistence.*; //订单(多方) @Entity @Table(name="ORD_INFO") public class Orders { @Id @GeneratedValue(strategy=GenerationType.AUTO) private int id; private String orderno; /** 多方*/ @ManyToOne(fetch=FetchType.LAZY, //cascade=CascadeType.ALL, targetEntity=Customers.class) /** 生成外键列*/ @JoinColumn(name="C_ID",referencedColumnName="CUS_ID") private Customers customers; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getOrderno() { return orderno; } public void setOrderno(String orderno) { this.orderno = orderno; } public Customers getCustomers() { return customers; } public void setCustomers(Customers customers) { this.customers = customers; } }
2.2.3 多对多
多方:
/** 多方*/ @ManyToMany(fetch=FetchType.LAZY, //延迟加载 targetEntity=Student.class, //指定目标对象 cascade=CascadeType.ALL, mappedBy="teachers") //老师不维护关联关系
另一个多方:
/** 多方*/ @ManyToMany(fetch=FetchType.LAZY, //延迟加载 targetEntity=Teacher.class) //目标对象 /** 中间表*/ @JoinTable(name="TEA_STU", //指定中间表名称 joinColumns=@JoinColumn(name="S_ID",referencedColumnName="STU_ID"), //@ManyToMany中没有加mappedby的主键列 inverseJoinColumns=@JoinColumn(name="T_ID",referencedColumnName="TEA_ID")) //@ManyToMany中加mappedby的主键列
还是通过老师(Teachers)和学生(Students)的例子说明:
Teachers.java
package edu.scut.f_AssoMap_double_n2n; import java.util.HashSet; import java.util.Set; import javax.persistence.*; //多方 @Entity @Table(name="TEA_INFO") public class Teacher { @Id @GeneratedValue(strategy=GenerationType.AUTO) @Column(name="TEA_ID") private int id; private String name; private String dept; /** 多方*/ @ManyToMany(fetch=FetchType.LAZY, //延迟加载 targetEntity=Student.class, //目标对象 cascade=CascadeType.ALL, mappedBy="teachers") //老师不维护关联关系 private Set
students = new HashSet (); 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; } public String getDept() { return dept; } public void setDept(String dept) { this.dept = dept; } public Set getStudents() { return students; } public void setStudents(Set students) { this.students = students; } } Students.java
package edu.scut.f_AssoMap_double_n2n; import java.util.HashSet; import java.util.Set; import javax.persistence.*; //多方 @Entity @Table(name="STU_INFO") public class Student { @Id @GeneratedValue(strategy=GenerationType.AUTO) @Column(name="STU_ID") private int id; private String name; private float score; /** 多方*/ @ManyToMany(fetch=FetchType.LAZY, //延迟加载 targetEntity=Teacher.class) //目标对象 /** 中间表*/ @JoinTable(name="TEA_STU", //指定中间表名称 joinColumns=@JoinColumn(name="S_ID",referencedColumnName="STU_ID"), //@ManyToMany中没有加mappedby的主键列 inverseJoinColumns=@JoinColumn(name="T_ID",referencedColumnName="TEA_ID")) //@ManyToMany中加mappedby的主键列 private Set
teachers = new HashSet (); 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; } public float getScore() { return score; } public void setScore(float score) { this.score = score; } public Set getTeachers() { return teachers; } public void setTeachers(Set teachers) { this.teachers = teachers; } }