更新時(shí)間:2022-12-27 16:53:20 來源:動力節(jié)點(diǎn) 瀏覽1080次
實(shí)體Player:玩家。
實(shí)體Game:游戲。
玩家和游戲是多對多的關(guān)系。一個(gè)玩家可以玩很多的游戲,一個(gè)游戲也可以被很多玩家玩。
JPA中使用@ManyToMany來注解多對多的關(guān)系,由一個(gè)關(guān)聯(lián)表來維護(hù)。這個(gè)關(guān)聯(lián)表的表名默認(rèn)是:主表名+下劃線+從表名。(主表是指關(guān)系維護(hù)端對應(yīng)的表,從表指關(guān)系被維護(hù)端對應(yīng)的表)。這個(gè)關(guān)聯(lián)表只有兩個(gè)外鍵字段,分別指向主表ID和從表ID。字段的名稱默認(rèn)為:主表名+下劃線+主表中的主鍵列名,從表名+下劃線+從表中的主鍵列名。
需要注意的:
1、多對多關(guān)系中一般不設(shè)置級聯(lián)保存、級聯(lián)刪除、級聯(lián)更新等操作。
2、可以隨意指定一方為關(guān)系維護(hù)端,在這個(gè)例子中,我指定Player為關(guān)系維護(hù)端,所以生成的關(guān)聯(lián)表名稱為: player_game,關(guān)聯(lián)表的字段為:player_id和game_id。
3、多對多關(guān)系的綁定由關(guān)系維護(hù)端來完成,即由Player.setGames(games)來綁定多對多的關(guān)系。關(guān)系被維護(hù)端不能綁定關(guān)系,即Game不能綁定關(guān)系。
4、多對多關(guān)系的解除由關(guān)系維護(hù)端來完成,即由Player.getGames().remove(game)來解除多對多的關(guān)系。關(guān)系被維護(hù)端不能解除關(guān)系,即Game不能解除關(guān)系。
5、如果Player和Game已經(jīng)綁定了多對多的關(guān)系,那么不能直接刪除Game,需要由Player解除關(guān)系后,才能刪除Game。但是可以直接刪除Player,因?yàn)镻layer是關(guān)系維護(hù)端,刪除Player時(shí),會先解除Player和Game的關(guān)系,再刪除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"))
????//關(guān)系維護(hù)端,負(fù)責(zé)多對多關(guān)系的綁定和解除
????//@JoinTable注解的name屬性指定關(guān)聯(lián)表的名字,joinColumns指定外鍵的名字,關(guān)聯(lián)到關(guān)系維護(hù)端(Player)
????//inverseJoinColumns指定外鍵的名字,要關(guān)聯(lián)的關(guān)系被維護(hù)端(Game)
????//其實(shí)可以不使用@JoinTable注解,默認(rèn)生成的關(guān)聯(lián)表名稱為主表表名+下劃線+從表表名,
????//即表名為player_game
????//關(guān)聯(lián)到主表的外鍵名:主表名+下劃線+主表中的主鍵列名,即player_id
????//關(guān)聯(lián)到從表的外鍵名:主表中用于關(guān)聯(lián)的屬性名+下劃線+從表的主鍵列名,即game_id
????//主表就是關(guān)系維護(hù)端對應(yīng)的表,從表就是關(guān)系被維護(hù)端對應(yīng)的表
????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")
????//只需要設(shè)置mappedBy="games"表明Game實(shí)體是關(guān)系被維護(hù)端就可以了
????//級聯(lián)保存、級聯(lián)刪除等之類的屬性在多對多關(guān)系中是不需要設(shè)置
????//不能說刪了游戲,把玩家也刪掉,玩家還可以玩其他的游戲
????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() {
????????//根據(jù)在persistence.xml中配置的persistence-unit name 創(chuàng)建EntityManagerFactory
????????emf = Persistence.createEntityManagerFactory("myJPA");
????}
?????
????@After
????public void after() {
????????//關(guān)閉EntityManagerFactory
????????if(null != emf) {
????????????emf.close();
????????}
????}
?????
????/**
?????* 創(chuàng)建玩家和游戲
?????*/
????@Test
????public void testSavePlayerAndGame() {
????????EntityManager em = emf.createEntityManager();
????????em.getTransaction().begin();
????????//因?yàn)镻layer和Game之間沒有級聯(lián)保存的關(guān)系,所以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);
?????????
????????//因?yàn)镻layer是關(guān)系的維護(hù)端,所以必須由Player來添加關(guān)系
????????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);
?????????
????????//因?yàn)镻layer是關(guān)系維護(hù)端,所以關(guān)系的解除由Player來完成
????????player.getGames().remove(game);
????????em.getTransaction().commit();
????????em.close();
????}
}
生成的關(guān)聯(lián)表結(jié)構(gòu)如下:
以上就是動力節(jié)點(diǎn)小編介紹的"jpa多對多的映射實(shí)例",希望對大家有幫助,如有疑問,請?jiān)诰€咨詢,有專業(yè)老師隨時(shí)為您務(wù)。
初級 202925
初級 203221
初級 202629
初級 203743