关联关系包括单向多对一、单向一对多、双向一对一、双向多对一和双向多对多共五种。
映射关联关系的具体实现代码下载地址:http://download.csdn.net/download/bingbeichen/9807425。
1. 映射单向多对一关联关系
以Customer和Order为例,多个Order可以同属于一个用户。
@Table(name="JPA_ORDERS")
@Entity
public class Order {
private Integer id;
private String orderName;
private Customer customer;
/**
* 映射单向多对一关联关系:
* 1). 使用@ManyToOne注解来映射单向多对一关联关系
* 2). 使用@JoinColumn注解来映射外键
* 3). 可以使用@ManyToOne的fetch属性设定关联属性的加载策略
* @return
*/
@JoinColumn(name="CUSTOMER_ID")
@ManyToOne(fetch=FetchType.LAZY)
public Customer getCustomer() {
return customer;
}
// ...
}
public class JPATestSingleManyToOne {
private EntityManagerFactory entityManagerFactory;
private EntityManager entityManager;
private EntityTransaction entityTransaction;
/**
* 单向多对一关联关系之保存:建议先保存1的一端再保存n的一端,以免额外多出UPDATE语句
*/
@Test
public void testManyToOnePersist() {
// 1端
Customer customer = new Customer(null, "qiaobb", "qiaobb@163.com", 23, new Date(), new Date());
// n端
Order order1 = new Order(null, "ORDER-JPA", customer);
Order order2 = new Order(null, "ORDER-HIBERNATE", customer);
// 保存1端
entityManager.persist(customer);
// 保存n端
entityManager.persist(order1);
entityManager.persist(order2);
}
/**
* 单向多对一关联关系之查找:
* 1). 默认情况下使用左外连接的方式来获取n的一端的对象及其关联的1的一端的对象
* 2). 可以使用@ManyToOne的fetch属性设定关联属性的加载策略
*/
@Test
public void testMangToOneFind() {
Order order = entityManager.find(Order.class, 1);
System.out.println(order.getOrderName());
System.out.println(order.getCustomer().getName());
}
/**
* 单向多对一关联关系之删除:不能直接删除1的一端,因为有外键约束
*/
@Test
public void testManyToOneRemove() {
// Order order = entityManager.find(Order.class, 1);
// entityManager.remove(order);
Customer customer = entityManager.find(Customer.class, 4);
entityManager.remove(customer);
}
/**
* 单向多对一关联关系之更新:
*/
@Test
public void testManyToOneUpdate() {
Order order = entityManager.find(Order.class, 1);
order.getCustomer().setName("sunaf");
}
@Before
public void init() {
String persistenceUnitName = "JPA-4-MappingRelation";
entityManagerFactory = Persistence.createEntityManagerFactory(persistenceUnitName);
entityManager = entityManagerFactory.createEntityManager();
entityTransaction = entityManager.getTransaction();
// 开启事务
entityTransaction.begin();
}
@After
public void destory() {
entityTransaction.commit();
entityManager.close();
entityManagerFactory.close();
}
}
2. 映射单向一对多关联关系
以Customer和Order为例,一个Customer可以有多个Order。
@Table(name = "JPA_CUSTOMERS")
@Entity
public class Customer {
private Integer id;
private String name;
private String email;
private Integer age;
private Date createTime;
private Date birthday;
private Set<Order> orders = new HashSet<>();
/**
* 映射单向一对多的关联关系:
* 1). 使用@@OneToMany注解来映射单向一对多关联关系
* 2). 使用@JoinColumn注解来映射外键列的名称
* 3). 可以使用@OneToMany的fetch属性修改默认的加载策略
* 4). 可以通过@OneToMany的cascade属性来修改默认的删除策略,如级联删除cascade={CascadeType.REMOVE}
* @return
*/
@JoinColumn(name="CUSTOMER_ID")
@OneToMany(fetch=FetchType.EAGER, cascade={CascadeType.REMOVE})
public Set<Order> getOrders() {
return orders;
}
// ...
}
public class JPATestSingleOneToMany {
private EntityManagerFactory entityManagerFactory;
private EntityManager entityManager;
private EntityTransaction entityTransaction;
/**
* 单向一对多关联关系之保存:会额外多出UPDATE语句,因为由n的一端维护关联关系
* n的一端在插入时不会同时插入外键列
*/
@Test
public void testOneToManyPersist() {
// 1端
Customer customer = new Customer(null, "qiaobb", "qiaobb@163.com", 23, new Date(), new Date());
// n端
Order order1 = new Order(null, "ORDER-JPA");
Order order2 = new Order(null, "ORDER-HIBERNATE");
// 建立关联关系
customer.getOrders().add(order1);
customer.getOrders().add(order2);
// 保存n端
entityManager.persist(order1);
entityManager.persist(order2);
// 保存1端
entityManager.persist(customer);
}
/**
* 单向一对多关联关系之查找:
* 1). 默认情况下对n的一端使用懒加载的加载策略
* 2). 可以使用@OneToMany的fetch属性修改默认的加载策略
*/
@Test
public void testOneToManyFind() {
Customer customer = entityManager.find(Customer.class, 1);
System.out.println(customer);
System.out.println(customer.getOrders());
}
/**
* 单向一对多关联关系之删除:默认情况下,删除1的一端时,则先把n的一端的外键置空,再进行删除
* 可以通过@OneToMany的cascade属性来修改默认的删除策略,如级联删除cascade={CascadeType.REMOVE}
*/
@Test
public void testOneToManyRemove() {
// Order order = entityManager.find(Order.class, 1);
// entityManager.remove(order);
Customer customer = entityManager.find(Customer.class, 1);
entityManager.remove(customer);
}
/**
* 单向一对多关联关系之更新:
*/
@Test
public void testOneToManyUpdate() {
Customer customer = entityManager.find(Customer.class, 2);
customer.getOrders().iterator().next().setOrderName("BBBBB");
}
@Before
public void init() {
String persistenceUnitName = "JPA-4-SingleOneToMany";
entityManagerFactory = Persistence.createEntityManagerFactory(persistenceUnitName);
entityManager = entityManagerFactory.createEntityManager();
entityTransaction = entityManager.getTransaction();
// 开启事务
entityTransaction.begin();
}
@After
public void destory() {
entityTransaction.commit();
entityManager.close();
entityManagerFactory.close();
}
}
3. 映射双向多对一关联关系
以Customer和Order为例,一个Customer可以有多个Order,多个Order也可以同属于一个Order。
// Customer类核心代码:
private Set<Order> orders = new HashSet<>();
// 若在1的一端@OneToMany中使用mappedBy="customer"属性,则1的一端不能再使用@JoinColumn标记
// 其中customer对应于n的一端的Customer属性名
// @JoinColumn(name="CUSTOMER_ID")
@OneToMany(fetch=FetchType.EAGER, cascade={CascadeType.REMOVE}, mappedBy="customer")
public Set<Order> getOrders() {
return orders;
}
// Order类核心代码:
private Customer customer;
@JoinColumn(name="CUSTOMER_ID")
@ManyToOne(fetch=FetchType.LAZY)
public Customer getCustomer() {
return customer;
}
// JPATestDoubleManyToOne类的核心测试代码:
/**
* 映射双向多对一的关联关系:
* 1). 先保存n的一端再保存1的一端,默认情况下双方均维护关联关系,额外多出2n条UPDATE语句
* 2). 先保存1的一端再保存n的一端,默认情况下双方均维护关联关系,额外多出1n条UPDATE语句
* 3). 建议n的一方来维护关联关系,而1的一方不维护关联关系,以减少额外多出的UPDATE语句
* 4). 若在1的一端@OneToMany中使用mappedBy="customer"属性,则1的一端不能再使用@JoinColumn标记
*/
@Test
public void testDoubleManyToOnePersist() {
Customer customer = new Customer(null, "CCC", "CCC@163.com", 33, new Date(), new Date());
Order order1 = new Order(null, "ORDER-CCC1");
Order order2 = new Order(null, "ORDER-CCC2");
customer.getOrders().add(order1);
customer.getOrders().add(order2);
order1.setCustomer(customer);
order2.setCustomer(customer);
// 执行保存操作
entityManager.persist(customer);
entityManager.persist(order1);
entityManager.persist(order2);
}
4. 映射双向一对一关联关系
映射双向一对一关联关系在执行保存操作时,默认不采用懒加载策略;可以在维护关联关系的一方使用懒加载策略,但不建议在不维护关联关系的一方使用。
5. 映射双向多对多关联关系
映射双向多对多关联关系在执行保存操作时,默认采用懒加载策略,即无论先获取哪一方,其对中间表而言均是平等的,均采用懒加载的方式。