首页 > 代码库 > Hibernate学习笔记_关系映射
Hibernate学习笔记_关系映射
一对一关联
一, 一对一单向外键关联
a) Annotation: 在被约束表字段的get方法上加@0ne20ne @JoinColumn
//Husband .java@Entitypublic class Husband { private int id; private String name; private Wife wife; @Id @GeneratedValue public int getId() { return id; } public String getName() { return name; } @OneToOne @JoinColumn(name="wifeId")//指定生成的数据库字段名 public Wife getWife() { return wife; } public void setId(int id) { this.id = id; } public void setName(String name) { this.name = name; } public void setWife(Wife wife) { this.wife = wife; } }
//Wife .java@Entitypublic class Wife { private int id; private String name; @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; } }
b) xml: 在被约束表的xml配置文件中加<many-to-one unique
<hibernate-mapping> <class name="com.bjsxt.hibernate.StuIdCard"> <id name="id"> <generator class="native"></generator> </id> <property name="num"/> <many-to-one name="student" column="studentId" unique="true"></many-to-one>//unique="true"是保证生成的字段唯一,这样<many-to-one 也达到了一对一的效果 </class> </hibernate-mapping>
二,一对一双向外键关联
a) Annotation: @0ne20ne(mappedBy=”…”)
规律:凡是双向关联,必设mappedBy
在Wife类中 写Husband对象属性 并添加注解@OneToOne(mappedBy="wife")
mappedBy作用 是指定这个一对一关联是被Husband类的 wife属性(准确说是getWife方法)做的映射
//Wife .java@Entitypublic class Wife { private int id; private String name; private Husband husband; @OneToOne(mappedBy="wife") //mappedBy作用 是指定这个一对一关联是被Husband类的 wife属性(准确说是getWife方法)做的映射 public Husband getHusband() { return husband; } public void setHusband(Husband husband) { this.husband = husband; } @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; } }
在Husband 类中写Wife对象属性
@Entitypublic class Husband { private int id; private String name; private Wife wife; @Id @GeneratedValue public int getId() { return id; } public String getName() { return name; } @OneToOne @JoinColumn(name="wifeId") public Wife getWife() { return wife; } public void setId(int id) { this.id = id; } public void setName(String name) { this.name = name; } public void setWife(Wife wife) { this.wife = wife; } }
此注释将由Husband表中生成wifeid字段作为fk外键,wife表中不生成额外的Husbandid字段
b) xml: many-to-one unique <one-to-one property-ref
在Student类中写StuIdCard属性, StuIdCard类中写Student属性
StuIdCard.hbm.xml文件中加
<hibernate-mapping> <class name="com.bjsxt.hibernate.StuIdCard"> <id name="id"> <generator class="native"></generator> </id> <property name="num"/> <many-to-one name="student" column="studentId" unique="true"></many-to-one> </class> </hibernate-mapping>
Student.hbm.xml文件中加
<hibernate-mapping> <class name="com.bjsxt.hibernate.Student" dynamic-update="true"> <id name="id"> <generator class="native"></generator> </id> <property name="name"></property> <property name="age" /> <property name="sex" /> <property name="good" type="yes_no"></property> <one-to-one name="stuIdCard" property-ref="student"></one-to-one> <!-- property-ref 相当于mappedBy--> </class> </hibernate-mapping>
其中, property-ref 相当于mappedBy
此方式生成的StuIdCard表中包含studentid字段作为fk外键, Student表中不生成额外的字段
特别说明: 一对一单向外键关联与一对一双向外键关联在数据库的表的格式是一样的,区别在于
java程序中. 双向外键关联可通过Hibernate在两个类间互相调用彼此,而单向外键关联只能单方向调用.
三, 一对一单向主键关联(不重要)
b) @primaryKeyJoinColumn
c) xml: <one-to-one id 使用 foreign class
四, 一对一双向主键关联(不重要)
b) @primaryKeyJoinColumn
c) xml: <one-to-one id 使用foreign class 和 <one-to-one property-ref
五, 联合主键
a) @JoinColumns
Wife类中建立联合主键,建立方式参考 ID生成策略中的联合主键部分
Husband类中写Wife对象属性,并在其get方法上写@OneToOne即可完成一对一外键映射
若想要指定生成的外键名 则需使用@JoinColumns注解,如下:
@Entitypublic class Husband { private int id; private String name; private Wife wife; @Id @GeneratedValue public int getId() { return id; } public String getName() { return name; }
/*@JoinColumns用于在一对一外键关联存在联合主键情况时指定生成的外键字段名称
@JoinColumns的参数为@JoinColumn数组 @JoinColumn内除需指定name属性外还需指定
referencedColumnName属性值 作用是可指定生成的字段名所对应的目标表字段名*/
@OneToOne @JoinColumns( { @JoinColumn(name="wifeId", referencedColumnName="id"), @JoinColumn(name="wifeName", referencedColumnName="name") } ) public Wife getWife() { return wife; } public void setId(int id) { this.id = id; } public void setName(String name) { this.name = name; } public void setWife(Wife wife) { this.wife = wife; } }
@Entity@IdClass(WifePK.class)public class Wife { private int id; private String name; private int age; public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Id public int getId() { return id; } public void setId(int id) { this.id = id; } @Id public String getName() { return name; } public void setName(String name) { this.name = name; } }
public class WifePK implements Serializable { 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; } }
组件映射
1 对象关系:一个对象是另外一个对象的一部分
2 数据库表:一张表
3 annotation: @Embbeded
对象模型
Husband(id,name,wife)
Wife(name,age)
Annotation:
在Husband的wife属性上建立注解
@Embedded 表明该对象是从别的位置嵌入过来的,是不需要单独映射的表.
这种方式生成的表为husband(id,name,wifename,wifeage),不会生成wife表.
@Entitypublic class Husband { private int id; private String name; private Wife wife; @Id @GeneratedValue public int getId() { return id; } public String getName() { return name; } @Embedded public Wife getWife() { return wife; } public void setId(int id) { this.id = id; } public void setName(String name) { this.name = name; } public void setWife(Wife wife) { this.wife = wife; } }
public class Wife { private String wifeName; private int age; public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getWifeName() { return wifeName; } public void setWifeName(String name) { this.wifeName = name; } }
@AttributeOverride注解需要写在getWife方法上,可以重新指定生成的Wife类组件生成的字段名,例如:Husband与Wife两个类中都有name字段,这样在生成表的时候会有冲突,此时采用@AttributeOverride注解可以指定Wife类中的name属性对应新的字段名—“wifename”,
不过@AttributeOverride注解不常用,因为有更好的解决方法. 1:不要在组件的两个映射类中写同名属性;2:如果真的有重复,那么可以在分类中(此处为Wife类)的重复名称的属性上使用如下内容以指定新的字段名:
@Column(name="wifename")
public String getName() {
return name;
}
4 xml: 使用<component,例如:
<hibernate-mapping> <class name="com.bjsxt.hibernate.Husband" > <id name="id"> <generator class="native"></generator> </id> <property name="name"></property> <component name="wife"> <property name="wifeName"></property> <property name="age"></property> </component> </class> </hibernate-mapping>
多对一与一对多
一, 多对一单向关联
实体模型(User多对一Group)
User(id,name,group)多
Group(id,name)一
1, annotaion: @Many2One
只需要在多的一端User属性group进行注解配置
@ManyToOne //多对一关联 User是多的一方 Group是一的一方
@JoinColumn(name="groupid") //指定User表中生成与Group对应的字段名
public Group getGroup() {
return group;
}
@Entity@Table(name="t_user")public class User { private int id; private String name; private Group group; @ManyToOne public Group getGroup() { return group; } public void setGroup(Group group) { this.group = group; } @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; }}
@Entity@Table(name="t_group")public class Group { private int id; private String name; @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; }}
2 xml: <many-to-one
<hibernate-mapping> <class name="com.bjsxt.hibernate.User" table="t_user"> <id name="id"> <generator class="native"></generator> </id> <property name="name"></property> <many-to-one name="group" column="groupId" /> </class> </hibernate-mapping>
<hibernate-mapping> <class name="com.bjsxt.hibernate.Group" table="t_group"> <id name="id"> <generator class="native"></generator> </id> <property name="name"></property> </class> </hibernate-mapping>
标签会在”多”的一端添加外键,相当于在数据库中添加外键
二, 一对多单向关联
a) 模型(group一对多user)
Group(id,name,users)一
User(id,name)多
设计时在一的这一端存在着多的集合,生成的数据库表通常是在多的一端生成外键.
Set<User> users = new HashSet<User>();
b) 类:在一的一方存在多方的集合
1, Annotation:@One2Many
在一的这一端Group端users属性上进行注解配置
@OneToMany //一对多关联 Group是一的一方 User是多的一方
@JoinColumn(name="groupid") //指定User表中生成与Group对应的字段名 注意此处与多对一配置方式不同
Hibernate默认将OneToMany理解为ManyToMany的特殊形式,如果不指定生成的外键列@JoinColumn(name="groupId"),则会默认生成多对多的关系,产生一张中间表。
@Entity@Table(name="t_group")public class Group { private int id; private String name; private Set<User> users = new HashSet<User>(); @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; } @OneToMany @JoinColumn(name="groupId") public Set<User> getUsers() { return users; } public void setUsers(Set<User> users) { this.users = users; }}
@Entity@Table(name="t_user")public class User { private int id; private String name; @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; }}
2,xml
配置一的那一端Group
<hibernate-mapping> <class name="com.bjsxt.hibernate.Group" table="t_group"> <id name="id"> <generator class="native"></generator> </id> <property name="name"></property> <set name="users"> <key column="groupId"></key> <one-to-many class="com.bjsxt.hibernate.User"/> </set> </class> </hibernate-mapping>
三, 一对多(多对一)双向关联
1,annotation
@Entity@Table(name="t_group")public class Group { private int id; private String name; private Set<User> users = new HashSet<User>(); @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; } @OneToMany(mappedBy="group") public Set<User> getUsers() { return users; } public void setUsers(Set<User> users) { this.users = users; }}
@Entity@Table(name="t_user")public class User { private int id; private String name; private Group group; @ManyToOne public Group getGroup() { return group; } public void setGroup(Group group) { this.group = group; } @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; }}
2,xml
<hibernate-mapping> <class name="com.bjsxt.hibernate.Group" table="t_group"> <id name="id"> <generator class="native"></generator> </id> <property name="name"></property> <set name="users"> <key column="groupId"></key> <one-to-many class="com.bjsxt.hibernate.User"/> </set> </class> </hibernate-mapping>
<hibernate-mapping> <class name="com.bjsxt.hibernate.User" table="t_user"> <id name="id"> <generator class="native"></generator> </id> <property name="name"></property> <many-to-one name="group" column="groupId"></many-to-one> </class> </hibernate-mapping>
务必确保在多的一端生成的生成的外键和一的一方生成的外键的名字相同,都为groupId.如果名字不同则会在多的一端生成多余的外键
多对多
一, 单向关联
a) 例如:老师和学生的关系,老师需要知道自己教了哪些学生
b) 数据库:生成中间表
1, Annotation:@Many2Many
Teacher类中写:(老师知道有哪些学生,学生不知道有哪些老师)
@Entitypublic class Teacher { private int id; private String name; private Set<Student> students = new HashSet<Student>(); @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; } @ManyToMany //多对多关联 Teacher是主的一方 Student是附属的一方 @JoinTable(name="t_s", //指定中间表名 joinColumns={@JoinColumn(name="teacher_id")}, //本类主键在中间表生成的对应字段 inverseJoinColumns={@JoinColumn(name="student_id")} //对方表主键在中间表生成的对应字段 ) public Set<Student> getStudents() { return students; } public void setStudents(Set<Student> students) { this.students = students; }}
@Entitypublic class Student { private int id; private String name; @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; }}
2, xml
<hibernate-mapping> <class name="com.bjsxt.hibernate.Teacher"> <id name="id"> <generator class="native"></generator> </id> <property name="name"></property> <set name="students" table="t_s"> <key column="teacher_id"></key> <many-to-many class="com.bjsxt.hibernate.Student" column="student_id"/> </set> </class> </hibernate-mapping>
二, 双向关联
a) 老师知道自己教了哪些学生,学生也知道教自己的有哪些老师
b) 数据库:生成中间表
1, Annotation:
@Entitypublic class Teacher { private int id; private String name; private Set<Student> students = new HashSet<Student>(); @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; } @ManyToMany @JoinTable(name="t_s", joinColumns={@JoinColumn(name="teacher_id")}, inverseJoinColumns={@JoinColumn(name="student_id")} ) public Set<Student> getStudents() { return students; } public void setStudents(Set<Student> students) { this.students = students; }}
@Entitypublic class Student { private int id; private String name; private Set<Teacher> teachers = new HashSet<Teacher>(); @ManyToMany(mappedBy="students") public Set<Teacher> getTeachers() { return teachers; } public void setTeachers(Set<Teacher> teachers) { this.teachers = teachers; } @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; }}
2, xml
<hibernate-mapping> <class name="com.bjsxt.hibernate.Teacher"> <id name="id"> <generator class="native"></generator> </id> <property name="name"></property> <set name="students" table="t_s"> <key column="teacher_id"></key> <many-to-many class="com.bjsxt.hibernate.Student" column="student_id"/> </set> </class> </hibernate-mapping>
<hibernate-mapping> <class name="com.bjsxt.hibernate.Student"> <id name="id"> <generator class="native"></generator> </id> <property name="name"></property> <set name="teachers" table="t_s"> <key column="student_id"></key> <many-to-many class="com.bjsxt.hibernate.Teacher" column="teacher_id"/> </set> </class> </hibernate-mapping>
Hibernate学习笔记_关系映射