hibernate中的@OneToMany、@ManyToOne以及@ManyToMany

一、一对多(@OneToMany)
1、单向一对多模型
假设通过一个客户实体可以获得多个地址信息。
对于一对多的实体关系而言,表结构有两种设计策略,分别是外键关联和表关联。
(1) 映射策略---外键关联
在数据库中表customer和表结构address定义,如下:

create table customer (
 
id int(20)notnull auto_increment,
 
name varchar(100),
  primary
key(id)
)

create table address (
 
id int(20)notnull auto_increment,
  province
varchar(50),
  city
varchar(50),
  postcode
varchar(50),
  detail
varchar(50),
  customer_id
int(20),
  primary
key (id)
)

1
 

注意此时外键定义在多的一方,也就是address表中。

 此时,表customer映射为实体CustomerEO,代码如下:

@Entity
@Table(name="customer")
public class CustomerEO implements java.io.Serializable {
 
@OneToMany(cascade={ CascadeType.ALL })
 
@JoinColumn(name="customer_id")
  private Collection<AddressEO> addresses = new ArrayList<AddressEO>();
...
}

1
 

注释@OneToMany的定义代码如下:

@Target({METHOD, FIELD}) @Retention(RUNTIME)
public @interface OneToMany {
 
Class targetEntity()defaultvoid.class;
  CascadeType[] cascade()
default {};
 
FetchType fetch()default LAZY;
 
String mappedBy()default "";
}

1
 

使用时要注意一下几点问题: 
a、targetEntity属性表示默认关联的实体类型。如果集合类中指定了具体类型了,不需要使用targetEntity.否则要指定targetEntity=AddressEO.class。 
b、mappedBy属性用于标记当实体之间是双向时使用。 

(2) 映射策略---表关联 

在上面address表中去掉customer_id字段,在增加一个表ref_customer_address,如下: --客户地址关系表
create table ref_customer_address (
  customer_id
int(20)notnull,
  address_id
int(20)notnull unique
)

1
 

此时表customer映射为CustomerEO实体,代码如下:

@Entity
@Table(name =
"customer")
public class CustomerEO implements java.io.Serializable {
  ...
  @
OneToMany(cascade = {CascadeType.ALL })
  @
JoinTable(name="ref_customer_address",
           joinColumns={ @
JoinColumn(name="customer_id",referencedColumnName="id")},
           inverseJoinColumns={@
JoinColumn(name="address_id",referencedColumnName="id")})
  private Collection<AddressEO> addresses = new ArrayList<AddressEO>();
  ...
}

1
 

表关联@JoinTable,定义如下:

@Target({METHOD,FIELD})
public
@interface JoinTable {
  String name() default "";
  String catalog() default "";
  String schema() default "";
 
JoinColumn[]joinColumns()default {};
 
JoinColumn[]inverseJoinColumns()default {};
 
UniqueConstraint[]uniqueConstraintsdefault {};
}

1
 

其中:
a、该标记和@Table相似,用于标注用于关联的表。
b、name属性为连接两张表的表名。默认的表名为:“表名1”+“-”+“表名2”,上面例子默认的表名为customer_address。
c、joinColumns属性表示,在保存关系中的表中,所保存关联的外键字段。
d、inverseJoinColumns属性与joinColumns属性类似,不过它保存的是保存关系的另一个外键字段。

(3) 默认关联
在数据库底层为两张表添加约束,如下:

create table customer_address (
  customer_id
int(20)notnull,
  address_id
int(20)notnull unique
)
alter table customer_address addconstraint fk_ref_customer foreignkey (customer_id)references customer (id);

alter table customer_address addconstraint fk_ref_address foreignkey (address_id)references address (id);

1
 


这样,在CustomerEO中只需要在标注@OneToMany即可!


二、多对一@ManyToOne
1、单向多对一模型。
(1) 外键关联
配置AddressEO实体如下:

@Entity
@Table(name="address")
public class AddressEO implements java.io.Serializable {

 
@ManyToOne(cascade = { CascadeType.ALL })
 
@JoinColumn(name="customer_id")
  private CustomerEO customer;

 
// ...
}

1
 

@ManyToOne定义如下:

@Target({METHOD,FIELD}) @Retention(RUNTIME)
public @interface ManyToOne { ClasstargetEntity()defaultvoid.class;
  CascadeType[] cascade()
default {};
 
FetchType fatch()default EAGER;
 
booleanoptional()defaulttrue;
}

1


(2) 默认关联
数据库脚本定义的相关字段的约束,创建外键后,直接使用@ManyToOne

三、高级一对多和多对一映射
即双向关联模型,确定了双向关联后,多的一方AddressEO不变使用@ManyToOne,而CustomerEO实体修改为:

@Entity
@Table(name="customer")
public class CustomerEO {

 
@OneToMany(mappedBy="customer")
  private Collection<AddressEO> addresses = new ArrayList<AddressEO>();

 
// ...
}

1
 

其中,@OneToMany标记中的mappedBy属性的值为AddressEO实体中所引用的CustomerEO实体的属性名。

四、多对多(@ManyToMany)
和一对多类型,不在赘述。@ManyToMany标记的定义如下:

@Target({METHOD, FIELD}) @Retention(RUNTIME)
public @interface ManyToMany { ClasstargetEntity()defaultvoid.class;
  CascadeType[] cascade()
default {};
 
FetchType fecth()default LAZY;
 
String mappedBy()default "";
}


1
现在再来讲解一下这几个注解中的属性含义:

一, CascadeType

CascadeType.PERSIST 级联新增(又称级联保存)
获取A对象里也同时也重新获取最新的B时的对象。即会重新查询数据库里的最新数据,并且,只有A类新增时,会级联B对象新增。若B对象在数据库存(跟新)在则抛异常(让B变为持久态),对应EntityManager的presist方法,调用JPA规范中的persist(),不适用于Hibernate的save()方法

  • CascadeType.MERGE 级联合并(又称级联更新)
    指A类新增或者变化,会级联B对象(新增或者变化) ,对应EntityManager的merge方法,调用JPA规范中merge()时,不适用于Hibernate的update()方法

  • CascadeType.REMOVE 级联删除
    只有A类删除时,会级联删除B类,即在设置的那一端进行删除时,另一端才会级联删除,对应EntityManager的remove方法,调用JPA规范中的remove()时,适用于Hibernate的delete()方法
  • CascadeType.REFRESH 级联刷新
    获取order(一或多)对象里也同时也重新获取最新的items(多)的对象,对应EntityManager的refresh(object),调用JPA规范中的refresh()时,适用于Hibernate的flush()方法
  • CascadeType.ALL
    包含所有持久化方法

    综上:大多数情况用CascadeType.MERGE就能达到级联跟新又不报错,用CascadeType.ALL时要斟酌下CascadeType.REMOVE

    二.FetchType
1、FetchType.LAZY:懒加载,加载一个实体时,定义懒加载的属性不会马上从数据库中加载。

2、FetchType.EAGER:急加载,加载一个实体时,定义急加载的属性会立即从数据库中加载。

3、比方User类有两个属性,name跟address,就像
百度知道 ,登录后用户名是需要显示出来的,此属性用到的几率极大,要马上到数据库查,用急加载;而用户地址大多数情况下不需要显示出来,只有在查看用户资料是才需要显示,需要用了才查数据库,用懒加载就好了。所以,并不是一登录就把用户的所有资料都加载到对象中,于是有了这两种加载模式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值