我的简化模型是:
Player
,谁可以玩游戏,Game
,可由玩家多次播放,Score
玩家收到玩游戏在我的实体映射中,Game
和Score
之间的关系是双向的,但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[ ]
,但p
和g
的返回值始终为null
(但计数正确且具有预期值)。但是当我将查询的第一行更改为SELECT p.id, g.id, COUNT(s.id)
时,返回的行包含p
和g
的预期ID。
我理解它可能因为延迟获取引用而发生,但是我怎么能强制查询检索p
和g
尽管被映射为惰性?我可以用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