• 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();
    	}
    }
    

      生成的关联表结构如下:

  • 相关阅读:
    eclipse快捷键失效
    git学习 branch log rebase merge fetch remote add push pull
    解决netty tcp自定义消息格式粘包/拆包问题
    多线程while(!state){}有问题,volatile优化,sleep睡着之后唤醒,刷新变量缓存
    玄学eclipse ,突然所有文件报错,然后,ctrl+a, ctrl+x, ctrl+v就好了
    玄学springboot applicationcontext.getBean(用类名String还是类型Class), getBean(..)的调用场景结果不同?getBean(..)还会阻塞?@DependsOn按照名称依赖,那么getBean用类名String
    玄学yml,被@ActiveProfiles注解误导
    玄学yml,被@ActiveProfiles注解误导
    java动态代理,多服务实例,线程安全target,注解,面向切面修改具有注解的方法行为,ThreadLocal<Object>
    java键盘输入方法-
  • 原文地址:https://www.cnblogs.com/luxh/p/2527123.html
Copyright © 2020-2023  润新知