實體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(); } }
生成的關聯表結構如下: