JPA multiselect在连接的返回值中返回null

时间:2016-12-07 10:11:04

标签: java hibernate jpa

我的简化模型是:

  • Player,谁可以玩游戏,
  • Game,可由玩家多次播放,
  • Score玩家收到玩游戏

在我的实体映射中,GameScore之间的关系是双向的,但Player不映射其所有Score的集合,只有Score => Player {1}}关系。我的JPA提供程序是Hibernate,我的关系映射使用默认FetchType(即FetchType没有显式值,可能使用lazy,因为这是Hibernate的默认值,尽管有JPA标准)。

现在我想计算每个玩家 p 每次玩 g 的次数,并省略几次播放的次数,然后我想出了以下查询:< / p>

SELECT p, g, COUNT(s.id)
FROM Score s JOIN 
     s.game g JOIN
     s.player p
WHERE *some additional filtering criteria, like games not being private etc*
GROUP BY p, g 
HAVING COUNT(s.id) >= :minimumGamesToQualify

当我运行以下代码时:

String strQuery = ...query above...;
Query query = em.createQuery(strQuery);
query.setParameter("criteriaParam", criteriaValue);
List result = query.getResultList();

返回列表包含(按预期方式)行Object[ ],但pg的返回值始终为null(但计数正确且具有预期值)。但是当我将查询的第一行更改为SELECT p.id, g.id, COUNT(s.id)时,返回的行包含pg的预期ID。 我理解它可能因为延迟获取引用而发生,但是我怎么能强制查询检索pg尽管被映射为惰性?我可以用JOIN FETCH以某种方式做到吗?

编辑:简化的映射和查询调用(删除了IMO与问题无关的部分):

@Entity
@Table(name = "\"Scores\"")
public class Score extends AbstractEntity {

    private String name;
    private Date scored_on;

    public Score() { }

    @Basic public String getName() { return name; }
    public void setName(String name) { this.name = name; }

    @Basic public Date getScored_on() { return scored_on; }
    public void setScored_on(Date scored_on) { this.scored_on = scored_on; }

    private Game game;
    @ManyToOne
    @JoinColumn(name="game_id", referencedColumnName="id")
    public Game getGame() { return game; }
    public void setGame(Game game) { this.game = game; }

    private Player player;
    @ManyToOne
    @JoinColumn(name="player_id", referencedColumnName="id")
    public Player getPlayer() { return player; }
    public void setPlayer(Player player) { this.player = player; }
}

@Entity
@Table(name="\"Games\"")
@XmlRootElement
public class Game extends AbstractEntity {

    private String name;
    @Basic public String getName() { return name; }
    public void setName (String  name) { this.name = name; }

    public Game() {    }

    private List<Score> scores = new ArrayList<Score>();

    @XmlTransient
    @OneToMany(mappedBy="game")
    public List<Score> getScores() { return scores; }
    public void setScores(List<Score> scores) { this.scores = scores; }
}

@Entity
@Table(name="\"Players\"")
public class Player extends AbstractEntity {

    private String firstname;
    private String lastname;
    private String email;

    public Player() { }

    @Basic public String getFirstname() { return firstname; }
    @Basic public String getLastname()  { return lastname; }
    @Basic public String getEmail()     { return email; }

    public void setFirstname(String firstname) { this.firstname = firstname; }
    public void setLastname(String lastname)   { this.lastname = lastname; }
    public void setEmail(String email)         { this.email = email; }

}

String strRelevantGamesQuery = "SELECT p, g, COUNT(s.Id) FROM Score s JOIN s.game g JOIN s.player p WHERE s.scored_on <= :scoredBefore GROUP BY p, g HAVING COUNT(s.Id) >= :minimumGamesPlayes";
TypedQuery<Object[]> queryRelevantGames = em.createQuery(strRelevantGamesQuery, Object[].class);
queryRelevantGames.setParameter("minimumGamesPlayes", 5L);
queryRelevantGames.setParameter("scoredBefore", summaryDate);
List<Object[]> resultRelevantGames = queryRelevantGames.getResultList();

//resultRelevantGames is a list of Object[3]. All row[0] and row[1] objects are null, row[2] contains correctly calculated counts.
//When I change query to: 
//    String strRelevantGamesQuery = "SELECT p.Id, g.Id, COUNT(s.Id) FROM...
//then all row[0] and row[1] contain correct IDs

0 个答案:

没有答案