1. 程式人生 > >JPA 五種 對映關係

JPA 五種 對映關係

一、JPA_對映單向多對一的關聯關係

1、建立實體類

//訂單
@Table(name="JPA_ORDER")
@Entity
public class Order {
	
	private Integer id;	
	private String orderName;	
	private Customer customer;

	@Id
	@GeneratedValue
	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	@Column(name="ORDER_NAME")
	public String getOrderName() {
		return orderName;
	}

	public void setOrderName(String orderName) {
		this.orderName = orderName;
	}

	//對映多對一的關聯關係
	//使用 @ManyToOne 來對映多對一的關聯關係
	//使用 @JoinColumn 來對映外來鍵  name:外來鍵鍵名
	@JoinColumn(name="CUSTOMER_ID")
	@ManyToOne
	public Customer getCustomer() {
		return customer;
	}

	public void setCustomer(Customer customer) {
		this.customer = customer;
	}
}

 測試類:

   //資料表生成
	@Test
	public void testManyToOne(){
		
	}

 儲存資料  :

儲存多對一時,建議先儲存1的一端,然後儲存 n 的一端,這樣不會多出額外的 UPDATE 語句

    @Test
	public void testManyToOnePersist(){
		Customer customer = new Customer();
		customer.setAge(15);
		customer.setBirth(new Date());
		customer.setCreatTime(new Date());
		customer.setEmail("
[email protected]
"); customer.setLastName("EE"); Order order1 = new Order(); order1.setOrderName("O-EE-1"); Order order2 = new Order(); order2.setOrderName("O-EE-2"); //設定關聯關係 order1.setCustomer(customer); order2.setCustomer(customer); //執行儲存操作 entityManager.persist(customer); entityManager.persist(order1); entityManager.persist(order2); }

   

 

輸出的SQL語句 : 是3 條insert 語句 

如果把執行儲存操作中調換順序

 @Test
	public void testManyToOnePersist(){
		Customer customer = new Customer();
		customer.setAge(15);
		customer.setBirth(new Date());
		customer.setCreatTime(new Date());
		customer.setEmail("[email protected]");
		customer.setLastName("GG");
		
		Order order1 = new Order();
		order1.setOrderName("g-GG-1");
		
		Order order2 = new Order();
		order2.setOrderName("g-GG-2");
		
		//設定關聯關係
		order1.setCustomer(customer);
		order2.setCustomer(customer);

        //執行儲存操作
		
        entityManager.persist(order1);
        entityManager.persist(order2);
		
        entityManager.persist(customer);

 那麼執行結果: 【可以儲存成功,SQL的變化】 三條insert 和兩條update

 

 

這個時候外來鍵是null 的 【下圖 中 CUSTOMER_ID外來鍵列的值 實際上為null 】

只有在儲存外這個customer 之後,才知道外來鍵列時誰,這個時候customer 才會有id; 【如下圖】

然後jpa去維護關聯關係,又額外有兩個update。所以總結:

獲取資料:

①、預設情況下,使用左外連線的方式來獲取 n 的一端的物件和其關聯的 1 的一端的物件

    @Test
	public void testManyToOneFind(){
		Order order = entityManager.find(Order.class, 1);
		System.out.println(order.getOrderName());
		
		System.out.println(order.getCustomer().getLastName());
	}

 執行的結果: 【一條select 語句】

 

 

②、可使用 @ManyToOne 中的 fetch 屬性來修改預設的關聯屬性的載入策略   【懶載入】

 還是同樣的測試 ,執行結果:  先生成Order 的資訊 , 再列印Customer --查詢customer 的語句 【兩條SQL語句】

刪除資料:

①、刪除

    @Test
	public void testManyToOneRemove(){
		Order order = entityManager.find(Order.class, 1);
		entityManager.remove(order);
	}

執行結果: 一個select 一個 delete 

②、不能直接刪除1 的一端,因為有外來鍵關聯

    @Test
	public void testManyToOneRemove(){
	
		Customer customer = entityManager.find(Customer.class, 7);
		entityManager.remove(customer);
		
	}

修改資料:

    @Test
	public void testManyToOneUpdate(){
		Order order = entityManager.find(Order.class, 2);
		order.getCustomer().setLastName("FFF");
		
	}

 

二、JPA_對映單向一對多的關聯關係

生成資料表:

    @Test
	public void testOneToMany(){
		
	}

儲存資料:

單向 1-n 關聯關係執行儲存時,一定會多出UPDATE語句,因為n 的一端在插入時不會同時插入外來鍵列

    @Test
	public void testOneToManyPersist(){
		Customer customer = new Customer();
		customer.setAge(18);
		customer.setBirth(new Date());
		customer.setCreatTime(new Date());
		customer.setEmail("[email protected]");
		customer.setLastName("ZZ");
		
		Order order1 = new Order();
		order1.setOrderName("O-ZZ-1");
		
		Order order2 = new Order();
		order2.setOrderName("O-ZZ-2");
		
		//建立關聯關係
		customer.getOrders().add(order1);
		customer.getOrders().add(order2);
		
		//執行儲存操作
		
		entityManager.persist(customer);
		entityManager.persist(order1);
		entityManager.persist(order2);	
	}

 結果是在控制檯輸出3條 insert 語句 和兩條 update語句

 

查詢資料:

①、預設對關聯的多的一方使用懶載入的載入策略

    @Test
	public void testOneToManyFind(){
		Customer customer = entityManager.find(Customer.class, 9);
		System.out.println(customer.getLastName());
		System.out.println(customer.getOrders().size());
	}

 

②、可以使用 @OneToMany 的fetch 屬性來修改預設的載入策略

測試:

    @Test
	public void testOneToManyFind(){
		Customer customer = entityManager.find(Customer.class, 9);
		System.out.println(customer.getLastName());
		System.out.println(customer.getOrders().size());
	}

執行結果變成了主外連線

刪除資料:

①、預設情況下,若刪除 1 的一端,則想把關聯 n 的一端的外來鍵置空,然後進行刪除

    @Test
	public void testOneToManyRemove(){
		Customer customer = entityManager.find(Customer.class, 9);
		entityManager.remove(customer);
	}

 執行結果  : 查詢,然後把外來鍵制空 , 最後刪除

   

   

②、可以通過修改 @OneToMany 的 cascade 屬性來修改預設的刪除策略

    //預設情況下,若刪除 1 的一端,則想把關聯 n 的一端的外來鍵置空,然後進行刪除
	//可以通過修改 @OneToMany 的 cascade 屬性來修改預設的刪除策略
	@Test
	public void testOneToManyRemove(){
		Customer customer = entityManager.find(Customer.class, 8);
		entityManager.remove(customer);
	}
	

 

 更新資料:

    @Test
	public void testOneToManyUpdate(){
		Customer customer = entityManager.find(Customer.class, 11);	
		customer.getOrders().iterator().next().setOrderName("O-xxx-11");
	}

  

三、JPA_對映雙向一對多的關聯關係  和雙向多對一是一樣的

1、實體類:   Order  的實體類 加上  private Customer customer;,Customer 的實體類不變

@Table(name="JPA_ORDERS")  //訂單
@Entity
public class Order {
	private Integer id;
	private String orderName;
	private Customer customer;

	@Id
	@GeneratedValue
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}

	@Column(name="ORDER_NAME")
	public String getOrderName() {
		return orderName;
	}
	public void setOrderName(String orderName) {
		this.orderName = orderName;
	}

	@JoinColumn(name="CUSTOMER_ID")
	@ManyToOne(fetch=FetchType.LAZY)
	public Customer getCustomer() {
		return customer;
	}
	public void setCustomer(Customer customer) {
		this.customer = customer;
	}
}

 儲存資料:

①、結論:若是雙向1 - n 的關聯關係,執行儲存時:

若是先儲存 n 的一端 , 再儲存 1 的一端,預設情況下會多出 4 (n) 條 UPDATE 語句。

若是先儲存 1 的一端,再儲存 n 的一端,預設情況下會多出 2(n)  條 UPDATE 語句

    @Test
	public void testOneToManyDouble(){
		Customer customer = new Customer();
		customer.setAge(18);
		customer.setBirth(new Date());
		customer.setCreatTime(new Date());
		customer.setEmail("[email protected]");
		customer.setLastName("yy");
		
		Order order1 = new Order();
		order1.setOrderName("O-YY-1");
		
		Order order2 = new Order();
		order2.setOrderName("O-YY-2");
		
		//建立關聯關係
		customer.getOrders().add(order1);
		customer.getOrders().add(order2);
		
		order1.setCustomer(customer);
		order2.setCustomer(customer);
		
		//執行儲存操作
		entityManager.persist(order1);
		entityManager.persist(order2);	

        entityManager.persist(customer);
	}

會有四條update 語句輸出 

 

②、控制檯多出2條 UPDATE 語句 

在進行雙向 1-n 關聯關係時,建議使用 n 的一方來維護關聯關係,而1 的一方不維護關聯關係,這樣會有效的減少SQL語句。

    @Test
	public void testOneToManyDouble2(){
		Customer customer = new Customer();
		customer.setAge(18);
		customer.setBirth(new Date());
		customer.setCreatTime(new Date());
		customer.setEmail("[email protected]");
		customer.setLastName("ss");
		
		Order order1 = new Order();
		order1.setOrderName("O-SS-1");
		
		Order order2 = new Order();
		order2.setOrderName("O-SS-2");
		
		//建立關聯關係
		customer.getOrders().add(order1);
		customer.getOrders().add(order2);
		
		order1.setCustomer(customer);
		order2.setCustomer(customer);
		
		//執行儲存操作  =====》 更改順序
		entityManager.persist(order1);
		entityManager.persist(order2);	
		
		entityManager.persist(customer);
	}

 結果大家自己去實現之後的控制檯看吧 ,資料已經成功的儲存在資料庫裡了。

③、注意:若在 1 的一端的 @OneToMany  中使用  mappedBy 屬性,則 @OneToMany 端就不能再使用 @JoinColumn 屬性了。

四、JPA_對映雙向一對一的關聯關係

 

五、JPA_對映雙向多對多的關聯關係