您的位置:首页 > 其它

Hibernate入门(5):关联映射&继承映射

2017-09-07 22:33 447 查看

关联映射

1、除了关系型数据库本身提供的基于关系的关联映射,Hibernate 也提供了面向对象的关联映射支持,这些关联关系大大简化了持久层数据的访问;2、Hibernate提供的关联关系可以分为以下2种,可以根据需求选择关联形式;单向关联:只能从一端访问另一端;双向关联:两端都可以相互访问;
3、单向关联包含以下4种关系:1-1(一对一),1-N(一对多),N-1(多对一),N-N(多对多); 4、双向关联包含以下3种关系(双向关联中1-N,N-1完全相同):1-1,1-N,N-N;
5、对于这些关联关系,hibernate 提供了以下4个注解支持:@OneToOne:1-1关系@OneToMore:1-N关系@MoreToOne:N-1关系@MoreToMore:N-N关系这些注解支持的常用属性如下:
cascade指定对于关联主体的级联策略,不设置时,不启用级联,可选值如下:
CascadeType.ALL:将所有的持久化操作级联到关联实体;
CascadeType.MERGE:将merge操作级联到关联实体;
CascadeType.PRESIST :将presist操作级联到关联实体;
CascadeType.REFRESH 
4000
:将refresh操作级联到关联实体;
CascadeType.REMOVE :将remove操作级联到关联实体;
fetch指定抓取关联实体的策略,可选值如下:
FetchType.EAGER:立即抓取
FetchType.:LAZY:延迟抓取(默认值)
mappedBy指定关联实体中那个属性值可以被引用到当前实体,值为关联实体的某个属性名;
当@OneToMany @ManyToMany 指定了该属性后,表明当前实体不能控制关联关系;
当某一段使用mappedBy放弃控制权后,该一段不能使用@JoinColumn,@JoinTable
orphanRemoval设置是否删除“孤儿”实体,如果某个实体所关联的父实体不存在,该实体为孤儿实体
tragetEntity该属性关联实体的类名,默认情况下 hibernate 会通过反射来判断关联实体的类名
6、对于1-N 关联关系,在数据库建模角度来讲,这两个关联的表存在基于外键分别为主表、从表的约束关系,hibernate有2种方式来进行表示:①组件映射:将从表记录映射为持久化类的组件,参见04. Hibernate 集合映射&组件映射,这种方式下 Hibernate 默认启用级联操作,组件的声明周期依赖于父对象:父对象保存时,组件被保存,父对象被删除时,组件被删除;②关联映射:将从表记录映射为持久化实体,这种方式下 hibernate 默认不开启级联操作,从表实体的拥有自己的声明周期,从而允许其他实体共享对其的引用;
7、Hibernate 支持有连接表和无连接表的关联映射;无连接表时,需要使用 @JoinColumn ,来映射外键列,支持属性如下:
name指定外键列列名
columnDefinition使用指定的SQL片段创建外键列
nullable指定该列是否允许为null,默认值 true
table指定该列的所在数据表的表名
unique指定是否为该列增加唯一约束,默认值 false
referenceColumnName指定所参照的主键列的列名
有连接表时,需要使用 @JoinTable,来映射底层连接表的信息,支持属性如下:
name指定连接表的表名
targetEntity指定关联实体的类名,默认Hibernate通过反射来判断关联实体的类名
joinColumns可接受多个 @JoinColumn,用与配置连接表中的外键列信息,这些外键参照当前实体对应表的主键列
inverseJoinColumns可接受多个 @JoinColumn,用与配置连接表中的外键列信息,这些外键参照关联实体对应表的主键列
uniqueConstrains为链接表增加唯一约束

单向 N-1 关联

1)无连接表的单向 N-1关联示例使用数据表,多个person可能拥有同一个address;
tableperson
columnperson_id (primary key)
address_id (foreign key)
person_name
tableaddress
columnaddress_id (primary key)
address_detial
Person.java
import javax.persistence.*;

@Entity
@Table(name="persion")
public class Person {
@Id @Column(name="person_id")
private int id;
@Column(name="persion_name")
private String name;

//定义Persion实体关联的Address实体
@ManyToOne(targetEntity = Address.class,cascade = CascadeType.ALL)   //N-1关联,启用所有级联操作
@JoinColumn(name="address_id",referencedColumnName="address_id" ,nullable = false)    //映射外键列
private Address address;

//省略所有getter,setter方法
}

address.java
import javax.persistence.*;

@Entity
@Table(name="address")
public class Address {
@Id @Column(name="address_id")
private int id;
@Column(name="addrrss_detail")
private String detial;

//省略所有 getter,setter方法

}
2)有关联表的单向 N-1关联
示例数据表如下:
tableperson
columnperson_id (primary key)
person_name
tableaddress
columnaddress_id (primary key)
address_detial
tableperson_address
columnperson_id (foreign key) 
address_id (foreign key)
id (primary key)
Person.java
import javax.persistence.*;
@Entity
@Table(name="person")
public class Persion {
@Id @Column(name="person_id")
private int id;
@Column(name="person_name")
private String name;

//定义Persion实体关联的Address实体
@ManyToOne(targetEntity = Address.class,cascade = CascadeType.ALL)   //N-1关联,启用所有级联操作
//映射连接表
@JoinTable(name="person_address",             //指定连接表名称
joinColumns = @JoinColumn(name="person_id",referencedColumnName = "person_id",unique=true),    //连接表外键对当前实体主键的参照
inverseJoinColumns = @JoinColumn(name="address_id",referencedColumnName = "address_id"))  //连接表外键对关联实体主键的参照
private Address address;

//省略所有getter,setter方法
}

address.java  同上

单向 1-N 关联

对于 1-N 关联,Hibernate 推荐使用双向关联,同时不让1的一端控制关联关系,而使用N的一端控制关联关系,当程序不得不使用使用单向的 1-N,优先采用连接表的 1-N 关联;

单向 1-1 关联

单向 1-1 关联一般使用的是无连接表的映射方式;Person.java
import javax.persistence.*;

@Entity
@Table(name="person")
public class Persion {
@Id @Column(name="person_id")
private int id;
@Column(name="person_name")
private String name;

//定义Persion实体关联的Address实体
@OneToOne(targetEntity = Address.class,cascade = CascadeType.ALL)   //1-1关联,启用所有级联操作
@JoinColumn(name="address_id",referencedColumnName="address_id" ,nullable = false, unique = true)    //映射外键列
private Address address;

//省略所有getter,setter方法
}

单向 N-N 关联

单向 N-N 关联的代码和 单向 1-N 的代码几乎完全相同,控制关系的一端只需要增加一个Set类型的属性即可;一般 N-N 关联使用连接表的形式进行关联;Person.java
@Entity
@Table(name="person")
public class Persion {
@Id @Column(name="person_id")
private int id;
@Column(name="person_name")
private String name;

//定义Persion实体关联的Address实体
@ManyToMany(targetEntity = Address.class,cascade = CascadeType.ALL)   //N-N关联,启用所有级联操作
//映射连接表
@JoinTable(name="person_address",             //指定连接表名称
joinColumns = @JoinColumn(name="person_id",referencedColumnName = "person_id"),    //连接表外键对当前实体主键的参照
inverseJoinColumns = @JoinColumn(name="address_id",referencedColumnName = "address_id"))  //连接表外键对关联实体主键的参照
private Set<Address> addresses = new HashSet<>();

//省略所有getter,setter方法
}

双向 1-N 关联

大部分时候,双向 1-N 关联使用无连接表的形式进行映射即可;1)无连接表的双向 1-N 关联
tableperson
columnperson_id (primary key)
person_name
tableaddress
columnaddress_id (primary key)
person_id (foreign key)
address_detial
Person.java
@Entity
@Table(name="person")
public class Person {
@Id @Column(name="person_id")
private int id;
@Column(name="person_name")
private String name;

@OneToMany(targetEntity = Address.class,cascade = CascadeType.ALL,mappedBy = "person")   //1-N关联,取消本实体的关联控制
private Set<Address> addresses = new HashSet<>();

//省略所有getter,setter方法
}
Address.java
@Entity
@Table(name="address")
public class Address {
@Id @Column(name="address_id")
private int id;
@Column(name="addrrss_detail")
private String detial;

@ManyToOne(targetEntity = Person.class,cascade=CascadeType.ALL)
@JoinColumn(name="person_id",referencedColumnName = "person_id",nullable = false)
private Person person;

//省略所有 getter,setter方法

}


2)有连接表的双向 1-N 关联Persion.java
@Entity
@Table(name="person")
public class Person {
@Id @Column(name="person_id")
private int id;
@Column(name="person_name")
private String name;

@OneToMany(targetEntity = Address.class,cascade = CascadeType.ALL,mappedBy = "person")   //1-N关联,取消本实体的关联控制
private Set<Address> addresses = new HashSet<>();
//省略所有getter,setter方法
}
Address.java
@Entity
@Table(name="address")
public class Address {
@Id @Column(name="address_id")
private int id;
@Column(name="addrrss_detail")
private String detial;

@ManyToOne(targetEntity = Person.class,cascade=CascadeType.ALL)
@JoinTable(name="person_address",
joinColumns = @JoinColumn(name="adddress_id",referencedColumnName = "address_id",unique=true),
inverseJoinColumns = @JoinColumn(name="person_id",referencedColumnName = "person_id"))
private Person person;

//省略所有 getter,setter方法

}


双向 1-1 关联
双向 1-1 关联一般使用无连接表的形式进行映射Person.java
@Entity
@Table(name="person")
public class Person {
@Id @Column(name="person_id")
private int id;
@Column(name="person_name")
private String name;

@OneToOne(targetEntity = Address.class,cascade = CascadeType.ALL,mappedBy="person")   //1-N关联,取消本实体的关联控制
private Address address;
//省略所有getter,setter方法
}
address.java
@Entity
@Table(name="address")
public class Address {
@Id @Column(name="address_id")
private int id;
@Column(name="addrrss_detail")
private String detial;

@ManyToOne(targetEntity = Person.class,cascade=CascadeType.ALL)
@JoinColumn(name="person_id",referencedColumnName = "person_id",unique=true)
private Person person;

//省略所有 getter,setter方法

}


双向 N-N 关联

一般双向N-N关联,使用连接表的形式映射;Person.java
@Entity
@Table(name="address")
public class Address {
@Id @Column(name="address_id")
private int id;
@Column(name="addrrss_detail")
private String detial;

@ManyToOne(targetEntity = Person.class,cascade=CascadeType.ALL)
@JoinColumn(name="person_id",referencedColumnName = "person_id",unique=true)
private Person person;

//省略所有 getter,setter方法

}
Address.java
@Entity
@Table(name="address")
public class Address {
@Id @Column(name="address_id")
private int id;
@Column(name="addrrss_detail")
private String detial;

@ManyToOne(targetEntity = Person.class,cascade=CascadeType.ALL)
@JoinTable(name="person_address",
joinColumns = @JoinColumn(name="adddress_id",referencedColumnName = "address_id"),
inverseJoinColumns = @JoinColumn(name="person_id",referencedColumnName = "person_id"))
private Set<Person> persons = new HashSet<>();
//省略所有 getter,setter方法

}


继承映射

hibernate 支持将继承层次结构与数据表进行映射,其定义了3种继承映射的策略:① 每个类层次对应一张表的映射策略;② 每个具体类对应一张表的映射策略;③ 连接子类的映射策略;
以下使用图示的继承层次进行示例说明:


每个类层次对应一张表的映射策略

这是Hibernate默认的继承映射策略,在这种策略下,整个继承层次结构都储存在一张表中,如上继承层次中 Employee,Regular_Emplee,Constract_Employee 3个实体都储存在同一张表中;使用这种策略时,Hibernate 会为该表额外创建一列,该列用于区分每行记录为哪一个类的实例,该列为辨别者列(discriminiator),使用@DiscriminatorColumn配置辨别者列,
Employee.java
@Entity
@Table(name = "employee")
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)           //标注继承方式为单表方式
@DiscriminatorColumn(name="type",discriminatorType=DiscriminatorType.STRING)       //指定辨别者列的数据类型
@DiscriminatorValue(value="employee")    //指定该实体的辨别者列值
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private int id;

@Column(name = "name")
private String name;

// setters and getters
}
Regular_Employee.java
@Entity
@DiscriminatorValue("regularemployee")
public class Regular_Employee extends Employee {

@Column(name = "salary")
private float salary;

@Column(name = "bonus")
private int bonus;

// setters and getters
}
Contract_Employee.java
@Entity
@DiscriminatorValue("contractemployee")
public class Contract_Employee extends Employee {

@Column(name = "pay_per_hour")
private float pay_per_hour;

@Column(name = "contract_duration")
private String contract_duration;

// setters and getters
}

每个具体类对应一张表的映射策略

这一种策略为每一个具体类对应一个具体的数据表,一般不会使用这种策略,因为有可能会导致数据过渡冗余;Employee.java
@Entity
@Table(name = "employee")
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private int id;

@Column(name = "name")
private String name;

// setters and getters

}

Regular_Employee.java
@Entity
@Table(name = "regularemployee")
@AttributeOverrides({
@AttributeOverride(name = "id", column = @Column(name = "id")),
@AttributeOverride(name = "name", column = @Column(name = "name")) })
public class Regular_Employee extends Employee {

@Column(name = "salary")
private float salary;

@Column(name = "bonus")
private int bonus;

// setters and getters

}
Contract_Employee.java
@Entity
@Table(name = "contractemployee")
@AttributeOverrides({
@AttributeOverride(name = "id", column = @Column(name = "id")),
@AttributeOverride(name = "name", column = @Column(name = "name")) })
public class Contract_Employee extends Employee {

@Column(name = "pay_per_hour")
private float pay_per_hour;

@Column(name = "contract_duration")
private String contract_duration;

// setters and getters
}


连接子类的映射策略

采用这种映射策略时,父类的实体保存在父类表里,而子类的实体则由父类表和子类表共同储存,即将子类和父类共同的属性存储在父类表中;Employee.java
@Entity
@Table(name = "employee")
@Inheritance(strategy = InheritanceType.JOINED)
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private int id;

@Column(name = "name")
private String name;

// setters and getters
}
Regular_Employee.java
@Entity
@Table(name = "regularemployee")
@PrimaryKeyJoinColumn(name = "id")
public class Regular_Employee extends Employee {
@Column(name = "salary")
private float salary;

@Column(name = "bonus")
private int bonus;

// setters and getters
}
Contract_Employee.java
@Entity
@Table(name = "contractemployee")
@PrimaryKeyJoinColumn(name = "id")
public class Contract_Employee extends Employee {

@Column(name = "pay_per_hour")
private float pay_per_hour;

@Column(name = "contract_duration")
private String contract_duration;

// setters and getters

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: