关联关系映射,是映射关系中比较复杂的一种映射关系,总的说来有一对一、一对多和多对多几种关系。细分起来他们又有单向和双向之分
多的一方为关系维护端,关系维护端负责外键纪录的更新,关系被维护端没有权力更新外键纪录。
拥有mappedBy注解的实体类为关系被维护端,另外的实体类为关系维护端的。关系的维护端负责对关系(在多对多为中间关联表)的CRUD做操作。关系的被维护端不能进行该操作,不能维护关系。
单向 OneToOne
单向一对一是关联关系映射中最简单的一种,简单地说就是可以从关联的一方去查询另一方,却不能反向查询
单向一对一关系的拥有端
@Entity
public classPerson implements Serializable{
@Id
@GeneratedValue(strategy= GenerationType.AUTO)
privateLong id;
privateString name;
privateint age;
@OneToOne
privateAddress address;
//Getters&Setters
}
单向一对一关系的反端
@Entity
public classAddress implementsSerializable {
@Id
@GeneratedValue(strategy= GenerationType.AUTO)
privateLong id;
privateString street;
privateString city;
private String country;
//Gettes& Setters
}
这种单向的一对一关系在数据库中是以外键的形式被映射的。其中关系的发出端存储一个指向关系的接收端的一个外键, 缺省情况下这个外键的字段名称,是以它指向的表的名称加下划线“_”加“ID”组成的, 当然我们也可以根据我们的喜好来修改这个字段,修改的办法就是使用 @JoinColumn 这个注解
双向 OneToOne
双向一对一关系中的接受端
@Entity
publicclassAddress implements Serializable {
@Id
@GeneratedValue(strategy= GenerationType.AUTO)
privateLong id;
privateString street;
privateString city;
private String country;
@OneToOne(mappedBy="address")
private Person person;
//Gettes& Setters
}
双向关系有一方为关系的拥有端,另一方是关系的反端,也就是“Inverse”端。在这里例子中 Person 拥有这个关系,而 Address 就是关系的“Inverse”端。Address 中我们定义了一个 person 属性,在这个属性上我们使用了 @OneToOne 注解并且定义了他的“mappedBy”属性,这个在双向关系的“Inverse”端是必需的
双向OneToMany
双向一对多关系的接受端
@Entity
public class Person implementsSerializable {
@Id
@GeneratedValue(strategy= GenerationType.AUTO)
privateLong id;
privateString name;
privateint age;
@OneToMany(mappedBy= "person")
privateList<CellPhone> cellPhones;
//Getters and Setters
}
双向一对多关系的发出端
@Entity
public class CellPhone implementsSerializable {
@Id
@GeneratedValue(strategy= GenerationType.AUTO)
privateLong id;
privateString manufacture;
privateString color;
privateLong phoneNo;
@ManyToOne
privatePerson person;
//Getters and Setters
}
单向 ManyToMany
多对多关联关系中只能通过中间表的方式进行映射
单向多对多关系的发出端
@Entity
public classTeacher implements Serializable {
@Id
@GeneratedValue(strategy =GenerationType.AUTO)
private Long id;
private String name;
private Boolean gender;
private int age;
private int height;
@ManyToMany
private List<Student> students;
// Getters and Setters
}
单向多对多关系的反端
@Entity
public classStudent implements Serializable {
@Id
@GeneratedValue(strategy =GenerationType.AUTO)
private Long id;
private String name;
private Boolean gender;
private int age;
private int height;
//Getters and Setters
}
双向 ManyToMany
双向多对多关系的拥有端
@Entity
public classTeacher implements Serializable {
@Id
@GeneratedValue(strategy =GenerationType.AUTO)
private Long id;
private String name;
private Boolean gender;
private int age;
private int height;
@ManyToMany
private List<Student> students;
// Getters and Setters
}
双向多对多关系的反端
@Entity
public classStudent implements Serializable {
@Id
@GeneratedValue(strategy =GenerationType.AUTO)
private Long id;
private String name;
private Boolean gender;
private int age;
private int height;
@ManyToMany(mappedBy = "students")
private List<Teacher> teachers;
//Getters and Setters
}
JPA复合主键映射
一个实体的主键可能同时构成,当且仅当多个字段的值完全相同时,才认为是相同的实体对象。
复合主键映射时,通常构成将复合主键的多个字段单独抽取出来建一个类作为符合主键类。
符合主键类必须满足以下几点要求
必须实现Serializable接口。
必须有默认的public无参数的构造方法。
必须覆盖equals和hashCode方法。equals方法用于判断两个对象是否相同,EntityManger通过find方法来查找Entity时,是根据equals的返回值来判断的。
@Embeddable
public class AirLinePK implements Serializable {
@Column(nullable=false,length=3,name="LEAVECITY")
private String leavecity;
@Column(nullable=false,length=3,name="ARRIVECITY")
private String arrivecity;
public AirLinePK(){}
public AirLinePK(String leavecity, String arrivecity) {
this.leavecity = leavecity;
this.arrivecity = arrivecity;
}
@Override
public int hashCode() {
int hash = 0;
hash += (this.leavecity!=null&& this.arrivecity!=null ? (this.leavecity+ "-"+this.arrivecity).hashCode() : 0);
return hash;
}
@Override
public boolean equals(Object object) {
if (!(object instanceof AirLinePK)){
returnfalse;
}
AirLinePK other = (AirLinePK)object;
if (this.leavecity !=other.leavecity && (this.leavecity == null ||!this.leavecity.equalsIgnoreCase(other.leavecity))) return false;
if (this.arrivecity !=other.arrivecity && (this.arrivecity == null ||!this.arrivecity.equalsIgnoreCase(other.arrivecity))) return false;
return true;
}
//省略getter setter...
}
@Entity
public class AirLine implements Serializable {
@EmbeddedId
private AirLinePK id;
@Column(length=15)
private String airLineNum;
public AirLine(){}
@Override
public int hashCode() {
int hash = 0;
hash += (this.id != null ?this.id.hashCode() : 0);
return hash;
}
@Override
public boolean equals(Object object) {
if (!(object instanceof AirLine)) {
returnfalse;
}
AirLine other = (AirLine)object;
if (this.id != other.id &&(this.id == null || !this.id.equals(other.id))) return false;
return true;
}
//省略getter setter...
}
复合主键映射还有另一种映射方式
public class AirLinePK implements Serializable {
@Column(length=3)
private String leavecity;
@Column(length=3)
private String arrivecity;
public AirLinePK(){}
public AirLinePK(String leavecity, String arrivecity) {
this.leavecity = leavecity;
this.arrivecity = arrivecity;
}
@Override
public int hashCode() {
int hash = 0;
hash += (this.leavecity!=null&& this.arrivecity!=null ? (this.leavecity+ "-"+this.arrivecity).hashCode() : 0);
return hash;
}
@Override
public boolean equals(Object object) {
if (!(object instanceof AirLinePK)){
returnfalse;
}
AirLinePK other = (AirLinePK)object;
if (this.leavecity !=other.leavecity && (this.leavecity == null ||!this.leavecity.equalsIgnoreCase(other.leavecity))) return false;
if (this.arrivecity != other.arrivecity&& (this.arrivecity == null ||!this.arrivecity.equalsIgnoreCase(other.arrivecity))) return false;
return true;
}
//省略getter setter
}
@Entity
@IdClass(AirLinePK.class)
public class AirLine implements Serializable {
@Id private String leavecity;
@Id private String arrivecity;
@Column(length=15) private String airLineNum;
public AirLine(){}
//省略getter setter
}
javax.persistence.OneToOne
target Entity
表示该属性关联的实体类型.该属性通常不必指定,ORM框架根据属性类型自动判断targetEntity.
mappedBy
mappedBy
属性是 String 类型的属性。mappedBy
属性的值是当前实体在关联实体中的属性名称,使用 mappedBy
可以定义实体类之间的双向关系。
如果类之间是单向关系,不需要提供定义
如果类和类之间形成双向关系,我们就需要使用这个属性进行定义,否则可能引起数据一致性的问题。
cascade
cascade
属性的类型是 CascadeType[]
类型。cascade
属性定义实体和实体之间的级联关系。可以从 CascadeType.PERSIST
(级联新建)、CascadeType.REMOVE
(级联删除)、CascadeType.REFRESH
(级联刷新)、CascadeType.MERGE
(级联更新)中选择一个或多个。还有一个更方便的选择是使用 CascadeType.ALL
,表示选择上面全部四项。
fetch
fetch
属性是 FetchType
类型的属性。可选择项包括:FetchType.EAGER
和 FetchType.LAZY
。
前者表示关联关系的从类在主类加载的时候同时加载,后者表示关联关系的从类在自己被访问时才加载。
optional
optional
属性是 boolean 类型的属性。是否允许该字段为null,该属性应该根据数据库表的外键约束来确定,默认为true。默认值是 true。
javax.persistence.JoinColumn
name
默认为引用关系属性
/
字段的名称
+”_”+
被引用的主键列的名称
insertable
默认情况下字段可以插入到所有表列中
nullable
是否允许所属列包含空值
referencedColumnName
属性指定关联关系中的被维护端与关联关系中的维护端对应的表之间形成关联关系的字段名称,默认情况下假设在实体关系中,被引用的列名是被引用的主键列的名称
,
要指定其他列名,请将
referencedColumnName
设置为所需的
String
列名
,通常用于关联关系中的被维护端的关联字段不是自己的主键的情况
table
实体的所有持久字段存储到一个名称为实体类名称的数据库表中
unique
JPA 持续性提供程序假设允许所有列包含重复值
updatable
默认情况下,JPA 持续性提供程序假设它可以更新所有表列
columnDefinition
@OneToOne 注解定义
public @interface OneToOne{
Class targetEntity( ) default void.class;
CascadeType[] cascade( ) default {};
FetchType fetch( ) default EAGER;
boolean optional( ) default true;
String mappedBy( ) default "";
}
@JoinColumn注解定义
@Target({METHOD,FIELD}) @Retention(RUNTIME)
public @interfaceJoinColumn {
String name() default "";
String referencedColumnName() default"";
boolean unique() default false;
boolean nullable() default true;
boolean insertable() default true;
boolean updatable() default true;
String columnDefinition() default"";
String table() default "";
}