JPA的多對多映射


  實體Player:玩家。

  實體Game:游戲。

  玩家和游戲是多對多的關系。一個玩家可以玩很多的游戲,一個游戲也可以被很多玩家玩。

  JPA中使用@ManyToMany來注解多對多的關系,由一個關聯表來維護。這個關聯表的表名默認是:主表名+下划線+從表名。(主表是指關系維護端對應的表,從表指關系被維護端對應的表)。這個關聯表只有兩個外鍵字段,分別指向主表ID和從表ID。字段的名稱默認為:主表名+下划線+主表中的主鍵列名,從表名+下划線+從表中的主鍵列名。

 

  需要注意的:

  1、多對多關系中一般不設置級聯保存、級聯刪除、級聯更新等操作。

  2、可以隨意指定一方為關系維護端,在這個例子中,我指定Player為關系維護端,所以生成的關聯表名稱為: player_game,關聯表的字段為:player_id和game_id。

  3、多對多關系的綁定由關系維護端來完成,即由Player.setGames(games)來綁定多對多的關系。關系被維護端不能綁定關系,即Game不能綁定關系。

  4、多對多關系的解除由關系維護端來完成,即由Player.getGames().remove(game)來解除多對多的關系。關系被維護端不能解除關系,即Game不能解除關系。

  5、如果Player和Game已經綁定了多對多的關系,那么不能直接刪除Game,需要由Player解除關系后,才能刪除Game。但是可以直接刪除Player,因為Player是關系維護端,刪除Player時,會先解除Player和Game的關系,再刪除Player。


  Player.java如下:

package com.cndatacom.jpa.entity;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;


/**
 * 玩家
 * @author Luxh
 */
@Entity
@Table(name="player")
public class Player {
	
	@Id
	@GeneratedValue
	private Long id;
	
	/**玩家姓名*/
	@Column(length=32)
	private String name;
	
	
	/**玩家玩的游戲*/
	@ManyToMany 
	@JoinTable(name="player_game",joinColumns=@JoinColumn(name="player_id"),
					inverseJoinColumns=@JoinColumn(name="game_id"))
	//關系維護端,負責多對多關系的綁定和解除
	//@JoinTable注解的name屬性指定關聯表的名字,joinColumns指定外鍵的名字,關聯到關系維護端(Player)
	//inverseJoinColumns指定外鍵的名字,要關聯的關系被維護端(Game)
	//其實可以不使用@JoinTable注解,默認生成的關聯表名稱為主表表名+下划線+從表表名,
	//即表名為player_game
	//關聯到主表的外鍵名:主表名+下划線+主表中的主鍵列名,即player_id
	//關聯到從表的外鍵名:主表中用於關聯的屬性名+下划線+從表的主鍵列名,即game_id
	//主表就是關系維護端對應的表,從表就是關系被維護端對應的表
	private Set<Game> games = new HashSet<Game>();


	public Long getId() {
		return id;
	}


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


	public String getName() {
		return name;
	}


	public void setName(String name) {
		this.name = name;
	}


	public Set<Game> getGames() {
		return games;
	}


	public void setGames(Set<Game> games) {
		this.games = games;
	}
	
}

  Game.java如下:

  

package com.cndatacom.jpa.entity;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.Table;


/**
 * 游戲
 * @author Luxh
 */

@Entity
@Table(name="game")
public class Game {
	
	@Id
	@GeneratedValue
	private Long id;
	
	/**游戲名稱*/
	@Column(length=32)
	private String name;
	
	/**游戲擁有的玩家*/
	@ManyToMany(mappedBy="games")
	//只需要設置mappedBy="games"表明Game實體是關系被維護端就可以了
	//級聯保存、級聯刪除等之類的屬性在多對多關系中是不需要設置
	//不能說刪了游戲,把玩家也刪掉,玩家還可以玩其他的游戲
	private Set<Player> players = new HashSet<Player>();

	public Long getId() {
		return id;
	}

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

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Set<Player> getPlayers() {
		return players;
	}

	public void setPlayers(Set<Player> players) {
		this.players = players;
	}
	
 	
}

  簡單的測試如下:

  

package com.cndatacom.jpa.test;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import com.cndatacom.jpa.entity.Game;
import com.cndatacom.jpa.entity.Player;

public class TestManyToMany {
	
EntityManagerFactory emf = null;
	
	@Before
	public void before() {
		//根據在persistence.xml中配置的persistence-unit name 創建EntityManagerFactory
		emf = Persistence.createEntityManagerFactory("myJPA");
	}
	
	@After
	public void after() {
		//關閉EntityManagerFactory
		if(null != emf) {
			emf.close();
		}
	}
	
	/**
	 * 創建玩家和游戲
	 */
	@Test
	public void testSavePlayerAndGame() {
		EntityManager em = emf.createEntityManager();
		em.getTransaction().begin();
		//因為Player和Game之間沒有級聯保存的關系,所以Playe和Game要分別保存
		
		Player player = new Player();
		player.setName("西門吹雪");
		//保存Player
		em.persist(player);
		
		Game game = new Game();
		game.setName("大菠蘿3");
		//保存game
		em.persist(game);
		
		em.getTransaction().commit();
		em.close();
	}
	
	/**
	 * 給玩家添加游戲
	 */
	@Test
	public void testAddGameToPlayer() {
		EntityManager em = emf.createEntityManager();
		em.getTransaction().begin();
		//找出ID為1的玩家
		Player player = em.find(Player.class, 1L);
		//找出ID為1的游戲
		Game game = em.find(Game.class, 1L);
		
		Set<Game> games = new HashSet<Game>();
		games.add(game);
		
		//因為Player是關系的維護端,所以必須由Player來添加關系
		player.setGames(games);
		
		em.getTransaction().commit();
		em.close();
	}
	
	/**
	 * 玩家刪除游戲
	 */
	@Test
	public void testRemoveGameFormPlayer() {
		EntityManager em = emf.createEntityManager();
		em.getTransaction().begin();
		//找出ID為1的玩家
		Player player = em.find(Player.class, 1L);
		//找出ID為1的游戲
		Game game = em.find(Game.class, 1L);
		
		//因為Player是關系維護端,所以關系的解除由Player來完成
		player.getGames().remove(game);
		em.getTransaction().commit();
		em.close();
	}
}

  生成的關聯表結構如下:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM