1 这里的关系映射指的是对象之间的关系,并不是指数据库的关系,本章解决的问题是当对象之间处于
下列关系之一时,数据库表该如何映射,编程上该如何对待(红色为重点)
2 简化问题:
a) 怎么写 Annotation
b) 增删改査CRUD怎么写
3 —对一
a) 单向(主键、外键)
b) 双向(主键、外键)
c) 中间表
4 —对多
a) 一张主表,多张子表
5 组件映射
a) @Embeddable
b) @ Embedded
1 一对一单向外键关联
a) 项目名称:hibernate_0600_one2one_uni_fk
b) Annotation: 在被约束表字段的get方法上加@0ne20ne @JoinColumn
@OneToOne
@JoinColumn(name="wifeid")//指定生成的数据库字段名
publicWife getWife() {
return wife;
}
c) xml: 在被约束表的xml配置文件中加<many-to-one unique
<classname="com.bjsxt.pojo.StuIdCard">
<id name="id">
<generatorclass="native"></generator>
</id>
<propertyname="num"/>
<many-to-onename="student" column="studentId"unique="true">
</many-to-one>
</class>
unique="true"是保证生成的字段唯一,这样<many-to-one 也达到了一对一的效果
2 一对一双向外键关联
a) 项目名称:hibernate_0700_one2one_bi_fk^
b) Annotation: @0ne20ne(mappedBy=”…”)
规律:凡是双向关联,必设mappedBy
在Wife类中 写Husband对象属性 并添加注解@OneToOne(mappedBy="wife") mappedBy作用
是指定这个一对一关联是被Husband类的 wife属性(准确说是getWife方法)做的映射
@OneToOne(mappedBy="wife")
public Husband getHusband() {
return husband;
}
在 类中写Wife对象属性
@OneToOne
@JoinColumn(name="wifeid")//指定生成的数据库字段名
publicWife getWife() {
return wife;
}
此注释将由Husband表中生成wifeid字段作为fk外键,wife表中不生成额外的Husbandid字段
c) xml: many-to-one unique <one-to-oneproperty-ref
在Student类中写StuIdCard属性, StuIdCard类中写Student属性
StuIdCard.hbm.xml文件中加
<many-to-onename="student" column="studentId"unique="true"></many-to-one>
Student.hbm.xml文件中加
<one-to-onename="stuIdCard" property-ref="student"></one-to-one>
其中,property-ref 相当于mappedBy
此方式生成的StuIdCard表中包含studentid字段作为fk外键, Student表中不生成额外的字段
特别说明: 一对一单向外键关联与一对一双向外键关联在数据库的表的格式是一样的,区别在于
java程序中. 双向外键关联可通过Hibernate在两个类间互相调用彼此,而单向外键关联只能单方向调用.
3 一对一单向主键关联(不重要)
a) 项目名称:hibernate_0800_one2one_uni_pk
b) @primaryKeyJoinColumn
c) xml: <one-to-one id 使用 foreign class
4 一对一双向主键关联(不重要)
a) 项目名称:hibernate_0900_one2one_bi_pk
b) @primaryKeyJoinColumn
c) xml: <one-to-one id 使用foreign class和<one-to-one property-ref
5 联合主键
a) 项目名称:hibernate_1000_one2one_uni_fk_composite
b) @JoinColumns
Wife类中建立联合主键,建立方式参考 ID生成策略中的联合主键部分
Husband类中写Wife对象属性,并在其get方法上写@OneToOne即可完成一对一外键映射
若想要指定生成的外键名则需使用@JoinColumns注解,如下:
@OneToOne
@JoinColumns( { @JoinColumn(name ="wifeid", referencedColumnName = "id"),
@JoinColumn(name ="wifename", referencedColumnName = "name") })
/*@JoinColumns用于在一对一外键关联存在联合主键情况时指定生成的外键字段名称
@JoinColumns的参数为@JoinColumn数组 @JoinColumn内除需指定name属性外还需指定
referencedColumnName属性值作用是可指定生成的字段名所对应的目标表字段名*/
public Wife getWife() {……}
1 项目:hibernate_1100_component
2 对象关系:一个对象是另外一个对象的一部分
3 数据库表:一张表
4 annotation: @ Embeddable @Embbeded
对象模型
Husband(id,name,wife)
Wife(name,age)
Annotation:
在Husband的wife属性上建立注解
@Embedded 表明该对象是从别的位置嵌入过来的,是不需要单独映射的表.
这种方式生成的表为husband(id,name,wifename,wifeage),不会生成wife表.
@AttributeOverride注解需要写在getWife方法上,可以重新指定生成的Wife类组件生成的字段名,例如:Husband与Wife两个类中都有name字段,这样在生成表的时候会有冲突,此时采用@AttributeOverride注解可以指定Wife类中的name属性对应新的字段名—“wifename”,不过@AttributeOverride注解不常用,因为有更好的解决方法. 1:不要在组件的两个映射类中写同名属性;2:如果真的有重复,那么可以在分类中(此处为Wife类)的重复名称的属性上使用如下内容以指定新的字段名:
@Column(name="wifename")
public String getName() {
return name;
}
另外,@ Embeddable注解好像是写在分类(Wife类)的类名前的,不过好像不写也行
@Embeddable
public class Wife {… …}
5 xml: 使用<component,例如:
<class name="Husband" >
<id name="id">
<generator class="native"/>
</id>
<property name="name"></property>
<componentname="wife">
<propertyname="wifeName"/>
<propertyname="wifeAge"/>
</component>
</class>
1 多对一单向关联
a) 项目名称:hibernate_1200_many2one_uni
实体模型(User多对一Group)
User(id,name,group)多
Group(id,name)一
b) 数据库表设计:在多方加外键
错误做法:在一方加冗余
perosnid |
person name |
dreamid |
1 |
zhangsan |
1 |
1 |
zhangsan |
2 |
dreamid |
dreamdescr |
|
1 |
earn money |
|
2 |
eat a lot |
|
c) annotaion: @Many2One
只需要在多的一端User属性group进行注解配置
@ManyToOne //多对一关联 User是多的一方 Group是一的一方
@JoinColumn(name="groupid")//指定User表中生成与Group对应的字段名
public Group getGroup() {
return group;
}
d) xml: <many-to-one
<many-to-onename="group" column="groupId" />
标签会在”多”的一端添加外键,相当于在数据库中添加外键
生成的表为user(id,name,groupid),t_group(id,groupname)
属性cascade
<many-to-onename="group" column="groupid" cascade="all"/>
取值all,none,save-update,delete,对象间的级联操作,只对增删改起作用.
在存储时User时,设置了cascade="all"会自动存储相应的t_group.而不用管user关联的对象(通常情况下会优先存储关联的对象,然后再存储user).
2 一对多单向关联
a) 项目名称:hibernate_1300_one2many_uni
模型(group一对多user)
Group(id,name,users)一
User(id,name)多
设计时在一的这一端存在着多的集合,生成的数据库表通常是在多的一端生成外键.
Set<User> users = new HashSet<User>();
b) 类:在一的一方存在多方的集合
c) 数据库表同上
d) Annotation:@One2Many
在一的这一端Group端users属性上进行注解配置
@OneToMany //一对多关联Group是一的一方 User是多的一方
@JoinColumn(name="groupid") //指定User表中生成与Group对应的字段名 注意此处与多对一配置方式不同
Hibernate默认将OneToMany理解为ManyToMany的特殊形式,如果不指定生成的外键列@JoinColumn(name="groupId"),则会默认生成多对多的关系,产生一张中间表。
e) xml:<set<one2many
XML配置中配置一的那一端Group
<class name="com.hibernate.Group"table="t_group">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<setname="users">
<key column="groupId"/>指定生成外键字段的名字
<one-to-many class="com.pojo.User"/>
</set>
</class>
3 一对多(多对一)双向关联
一对多与多对一的双向关联是同一种情况.
关系模型(group一对多user)
Group(id,name,users)一
User(id,name,group)多
Set<User> users=newHashSet<User>()
配置规则:一般以多的一端为主,先配置多的一端
在多的一端User端配置group
@ManyToOne
@JoinColumn(name="groupid")
在一的一端Group端配置时,在users只需要加个mappedBy="groupid"
@OneToMany(mappedBy="group")
XML配置
Group中
<set name="users">
<keycolumn="groupId"/>
<one-to-manyclass="com.hibernate.User"/>
</set>
在User中
<many-to-one name="group"column="groupId"/>
务必确保在多的一端生成的生成的外键和一的一方生成的外键的名字相同,都为groupId.
如果名字不同则会在多的一端生成多余的外键
1 单向关联:
a) 项目:hibernate_1500_many2many_uni
关系模型(Teache多对多Student),从Teacher这一端能关联到students.
Teacher(id,name,students)多
Student(id,name)多
Set<Student>students=new HashSet<Student>()
在Teacher那一端配置
b) 例如:老师和学生的关系,老师需要知道自己教了哪些学生
c) 数据库:生成中间表
d) Annotation:@Many2Many
Teacher类中写:
private Set<Student>students = new HashSet<Student>();
@ManyToMany //多对多关联Teacher是主的一方 Student是附属的一方
@JoinTable(name="t_s", //指定中间表表名
joinColumns={@JoinColumn(name="teacherid")},//本类主键在中间表生成的
对应字段名
inverseJoinColumns={@JoinColumn(name="studentid")}//对方类主键在中间表
生成的对应字段名
)
public Set<Student> getStudents(){……}
e) XML:<many2many
<class name="com.xxx.Teacher">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<setname="students" table="t_s">table定义中间表的表名
<keycolumn="teacher_id"></key>
<many-to-manyclass="com.xxx.Student" column="student_id"/>
</set>
</class>
2 双向关联:
a) 项目:hibernate_1600_many2many_bi
多对多双向配置只需要在两端类进行配置就才可以.
关系模型(Teache多对多Student)
Teacher(id,name,students)多
Student(id,name,teachers)多
Set<Student> students = new HashSet<Student>()
Set<Teacher> teachers = newHashSet<Teacher>();
b) 老师知道自己教了哪些学生,学生也知道教自己的有哪些老师
c) 数据库:生成中间表
d) Annotation:
在Teacher这一端的students上配置
@ManyToMany
@JoinTable(name="t_s",
joinColumns={@JoinColumn(name="teacher_id")},
inverseJoinColumns={@JoinColumn(name="student_id")}
)
在Student一端的teachers只需要配置
@ManyToMany(mappedBy="students")
注意:mappedBy 与 @JoinTable等一类的配置要分开,不然表字段可能乱
e) XML:
XML配置方式:两端配置一样,注意表名和生成的中间表的字段属性名要一致
Teacher那一端配置
<setname="students" table="t_s">
<key column="teacher_id"/>
<many-to-many class="com.xxx.Student"column="student_id"/>
</set>
在Student那一端配置
<setname="teachers" table="t_s">
<key column="student_id"></key>
<many-to-many class="com.xxx.Teacher"column="teacher_id"/>
</set>
生成的数据库表和上面是一样的
036
在xml里面配一对一单向关联
用many-to-one来做一对一这个多对一是站在这个类的角度说的设定unique=”true”就约束了它是一对一
037 一对一双向外键关联
两个类都有对方类类型的属性 (两边都写)
然后加一个属性告诉hibernate外键关联是在husband的wife属性那边设好了他那边是主导 (括号里面的”wife”是指husband里面有一个属性wife)
凡是双向关联必设mappedBy
Xml的设法
038
单向和双向的映射在数据库里面是没有区别的区别在于 我们的model里面 是不是有对方这个属性 能不能从一方里面取到另一方
单向主键关联: 一方的id会参考另一方的id
只用将原来的@joinColumn(“”) 改成@PrimaryKeyJoinColumn 即可
这个有BUG不能自动在建数据库帮你做连接
XML设置 它会帮你生成一个外键 上面的设置令studentcard会参考student的id生成自己的id
038 一对一很少 如果有 一般使用外键映射 不用外键关联
一对一在数据库中可以放在一张表中而在软件中 还是可以分成两个对象(组件)
一对一双向
039 联合主键关联
假设wife用id 和name做联合主键
复习联合主键的写法类上面加Idclass 在所有的id上面加@id
记得! 联合主键要继承serializable 而且要重写HashCode() 和 equals()
在Husband的getWife上面这样写
041 组件 一张表 两个或多个类
其中wife里面不用用任何标签也不要有id
声明的时候也不用生明wife表因为她没有作为一张表存在
假如组件类和主要的类之间字段名有冲突 可以用@column解决
Xml的写法 声明husband的一个组件wife 其中有两个字段要保存到表
042 多对一单向关联 只用加@many-to-one
怕用到数据库的关键词命名数据库库表
可以在表的XML里面设定
043
一对多关联用一个集合来装 一定要制订关联的是users类里面的哪个属性 这样才能实现一对多 要不然hibernate会以为是多对多(BUG)
XML写法
044 多对一 一对多 双向关系
多的那边要写(mappedBy) 关联另一边的属性
Xml 配置
两边的column要一致
045 多对多
多对多单向
在有另一方集合的一方的getXX()函数上面写@manytomany即可
改变默认中间表名称为t_s
也可以设定中间表中的两个字段前者指定自己 后者制订另一个many的列名
Xml的 student那边不用many-to-many的column属性写的是对方的列名(student_id)