我有以下查询,希望在单个选择请求中运行:
@NamedQuery(name=Game.GET_GAME_BY_ID1, query = "SELECT g FROM Game g " + "JOIN FETCH g.team1 t1 " + "JOIN FETCH t1.players p1 " + "JOIN FETCH p1.playerSkill skill1 " + "where g.id=:id")
问题在于,所有内容都是通过单独的多个查询获取的。我只希望在单个请求中获取团队和团队的球员以及每个球员的技能。但是取而代之的是,我有多个选择查询来获取每个球队,每个球员,每个球员的统计数据和技能。
以下是带有给定注释的实体:
游戏实体:
public class Game implements Serializable { private Integer id; private Integer dayNumber; private Long date; private Integer score1; private Integer score2; private Team team1; private Team team2; .... @ManyToOne(fetch=FetchType.EAGER) @Fetch(FetchMode.JOIN) @JoinColumn(name="team_id1") public Team getTeam1() { return team1; } public void setTeam1(Team team1) { this.team1 = team1; } // uni directional many to one association to Team @ManyToOne(fetch=FetchType.EAGER) @Fetch(FetchMode.JOIN) @JoinColumn(name="team_id2") public Team getTeam2() { return team2; } public void setTeam2(Team team2) { this.team2 = team2; } }
团队实体:
public class Team implements Serializable { ... private Set<Player> players; ... @OneToMany(mappedBy="team", targetEntity=Player.class, fetch=FetchType.LAZY, cascade=CascadeType.ALL) @Fetch(FetchMode.JOIN) @OrderBy(value="batOrder, pitRotationNumber ASC") public Set<Player> getPlayers() { return players; } public void setPlayers(Set<Player> players) { this.players = players; } }
玩家实体:
public class Player implements Serializable { private PlayerStat playerStats; private PlayerSkill playerSkill; ... @OneToOne(mappedBy="player", cascade=CascadeType.ALL) @Fetch(FetchMode.JOIN) public PlayerStat getPlayerStats() { return this.playerStats; } public void setPlayerStats(PlayerStat playerStats) { this.PlayerStats = playerStats; } ... @OneToOne(mappedBy="player", fetch=FetchType.LAZY, cascade=CascadeType.ALL) @Fetch(FetchMode.JOIN) public PlayerSkill getPlayerSkill() { return this.playerSkill; } public void setPlayerSkill(PlayerSkill playerSkill) { this.playerSkill = playerSkill; } }
您能指出犯下的错误吗?我需要一个选择查询来加载游戏,它是团队,团队的球员和每个球员的技能。
编辑1: 这是postgresql日志(其中的一部分),纯sql查询:http : //pastebin.com/Fbsvmep6
为简单起见,在此问题中更改了表的原始名称,游戏是GamelistLeague,团队是TeamInfo,并且有BatterStats和PitcherStats而不是一个PlayerStats
日志中的第一个查询是上面这个问题中显示的查询(命名查询),如果我直接在数据库中执行查询,它将根据需要返回所有内容。
您正在遇到一个众所周知的问题,也就是“ N + 1选择”。简而言之,当您选择父实体时,“ N + 1选择”问题就会发生,并且休眠将使用OneToOne对与父相关的子项进行附加选择。因此,如果数据库中有“ N”个父子记录,hibernate将使所有父项具有一个选择,然后使每个子项处于单独的选择中,从而使N + 1个选择合计。 在休眠状态下,有两种方法可以解决“ N + 1”问题: 1.“加入获取” 所有 OneToOne子级。 2.启用二级缓存,并在OneToOne子级上使用@Cache批注。
您的问题是您没有“加入获取”所有的OneToOne子代。您必须“加入”所有对象,包括可传递的子代(从子代本身或集合中引用的实体)。
使OneToOne变得懒惰(因为默认情况下它很渴望)只是部分解决方案,因为仅当您访问子代上的某个getter时,休眠才会为子代选择一个选项,但是从长远来看,它仍然会使所有N个选择。