1. 程式人生 > >JPA - 雙向多對多對映

JPA - 雙向多對多對映

在雙向多對多關係中,我們必須指定一個關係維護端(owner side),可以通過 @ManyToMany 註釋中指定 mappedBy 屬性來標識其為關係維護端。

【1】item與Category

item:category = N:N ,item為關係維護端(主),category為從。

item類如下:

@Table(name="JPA_ITEMS")
@Entity
public class Item {

	private Integer id;
	private String itemName;
	
	private Set<Category> categories = new HashSet<>();

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

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

	@Column(name="ITEM_NAME")
	public String getItemName() {
		return itemName;
	}

	public void setItemName(String itemName) {
		this.itemName = itemName;
	}

	//使用 @ManyToMany 註解來對映多對多關聯關係
	//使用 @JoinTable 來對映中間表
	//1. name 指向中間表的名字
	//2. joinColumns 對映當前類所在的表在中間表中的外來鍵
	//2.1 name 指定外來鍵列的列名
	//2.2 referencedColumnName 指定外來鍵列關聯當前表的哪一列
	//3. inverseJoinColumns 對映關聯的類所在中間表的外來鍵
	@JoinTable(name="ITEM_CATEGORY",
			joinColumns={@JoinColumn(name="ITEM_ID", referencedColumnName="ID")},
			inverseJoinColumns={@JoinColumn(name="CATEGORY_ID", referencedColumnName="ID")})
	@ManyToMany
	public Set<Category> getCategories() {
		return categories;
	}

	public void setCategories(Set<Category> categories) {
		this.categories = categories;
	}
}

category類如下:

@Table(name="JPA_CATEGORIES")
@Entity
public class Category {

	private Integer id;
	private String categoryName;
	
	private Set<Item> items = new HashSet<>();

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

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

	@Column(name="CATEGORY_NAME")
	public String getCategoryName() {
		return categoryName;
	}

	public void setCategoryName(String categoryName) {
		this.categoryName = categoryName;
	}

	@ManyToMany(mappedBy="categories")
	public Set<Item> getItems() {
		return items;
	}

	public void setItems(Set<Item> items) {
		this.items = items;
	}
}

【2】多對多持久化操作

示例程式碼如下:

//多對多的儲存
	@Test
	public void testManyToManyPersist(){
		Item i1 = new Item();
		i1.setItemName("i-1");
	
		Item i2 = new Item();
		i2.setItemName("i-2");
		
		Category c1 = new Category();
		c1.setCategoryName("C-1");
		
		Category c2 = new Category();
		c2.setCategoryName("C-2");
		
		//設定關聯關係
		i1.getCategories().add(c1);
		i1.getCategories().add(c2);
		
		i2.getCategories().add(c1);
		i2.getCategories().add(c2);
		
		c1.getItems().add(i1);
		c1.getItems().add(i2);
		
		c2.getItems().add(i1);
		c2.getItems().add(i2);
		
		//執行儲存
		entityManager.persist(i1);
		entityManager.persist(i2);
		entityManager.persist(c1);
		entityManager.persist(c2);
	}
	

控制檯輸出如下:

Hibernate: 
    insert 
    into
        JPA_ITEMS
        (ITEM_NAME) 
    values
        (?)
Hibernate: 
    insert 
    into
        JPA_ITEMS
        (ITEM_NAME) 
    values
        (?)
Hibernate: 
    insert 
    into
        JPA_CATEGORIES
        (CATEGORY_NAME) 
    values
        (?)
Hibernate: 
    insert 
    into
        JPA_CATEGORIES
        (CATEGORY_NAME) 
    values
        (?)
Hibernate: 
    insert 
    into
        ITEM_CATEGORY
        (ITEM_ID, CATEGORY_ID) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        ITEM_CATEGORY
        (ITEM_ID, CATEGORY_ID) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        ITEM_CATEGORY
        (ITEM_ID, CATEGORY_ID) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        ITEM_CATEGORY
        (ITEM_ID, CATEGORY_ID) 
    values
        (?, ?)

資料庫結果如下:

這裡寫圖片描述


【3】雙向多對多獲取操作

先獲取非維護關聯關係的一方,程式碼示例如下:

	@Test
	public void testManyToManyFind(){
		Category category = entityManager.find(Category.class, 3);
		System.out.println(category.getCategoryName());
		System.out.println(category.getItems().size());
	}

控制檯輸出如下:

這裡寫圖片描述


如果先獲取維護關聯關係的一方呢?

示例程式碼如下:

	
	@Test
	public void testManyToManyFind(){
			Item item = entityManager.find(Item.class, 5);
			System.out.println(item.getItemName());
			
			System.out.println(item.getCategories().size());
		
	}

控制檯輸出如下:

這裡寫圖片描述


故而總結如下:

對於關聯的集合物件, 預設使用懶載入的策略;

使用維護關聯關係的一方獲取, 還是使用不維護關聯關係的一方獲取, SQL 語句相同。