Java JPA multiselect在联接返回值中返回null
我的简化模型是:Java JPA multiselect在联接返回值中返回null,java,hibernate,jpa,Java,Hibernate,Jpa,我的简化模型是: 玩家,可以玩游戏 游戏,玩家可以玩多次 得分玩家在玩给定游戏时收到 在我的实体映射中,Game和Score之间的关系是双向的,但是Player没有映射其所有Score的集合,只有Score=>Player关系。我的JPA提供程序是Hibernate,我的关系映射使用默认的FetchType(也就是说,FetchType没有显式的值,可能使用lazy,因为这是Hibernate的默认值,尽管JPA标准是这样的) 现在我想计算每个玩家p玩游戏g的次数,忽略玩过几次的玩家,我提出
,可以玩游戏玩家
,玩家可以玩多次游戏
玩家在玩给定游戏时收到得分
Game
和Score
之间的关系是双向的,但是Player
没有映射其所有Score
的集合,只有Score=>Player
关系。我的JPA提供程序是Hibernate,我的关系映射使用默认的FetchType
(也就是说,FetchType
没有显式的值,可能使用lazy,因为这是Hibernate的默认值,尽管JPA标准是这样的)
现在我想计算每个玩家p玩游戏g的次数,忽略玩过几次的玩家,我提出了以下查询:
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();
返回的列表(如预期)包含
对象[]
的行,但p
和g
的返回值总是null
(但计数计算正确且具有预期值)。但当我将查询的第一行更改为SELECT p.id、g.id、COUNT(s.id)
时,返回的行包含p
和g
的预期id。
我知道这可能是因为懒散地获取引用,但是我如何强制查询检索p
和g
,尽管被映射为懒散?我可以用JOIN FETCH
以某种方式完成吗
编辑:简化映射和查询调用(删除了IMO与问题无关的部分):
@实体
@表(name=“\”分数\”)
公共类分数扩展了抽象实体{
私有字符串名称;
私人日期:年月日;
公共分数(){}
@基本公共字符串getName(){return name;}
public void setName(字符串名){this.name=name;}
@基本公共日期getScored_on(){return scored_on;}
公共无效设置得分日期{this.scored\u on=scored\u on;}
私人游戏;
@许多酮
@JoinColumn(name=“game\u id”,referencedColumnName=“id”)
公共游戏getGame(){return Game;}
public void setGame(Game Game){this.Game=Game;}
私人玩家;
@许多酮
@JoinColumn(name=“player\u id”,referencedColumnName=“id”)
公共播放器getPlayer(){return Player;}
public void setPlayer(Player){this.Player=Player;}
}
@实体
@表(name=“\”Games\”)
@XmlRootElement
公共类博弈扩展抽象实体{
私有字符串名称;
@基本公共字符串getName(){return name;}
public void setName(字符串名){this.name=name;}
公共游戏(){}
私有列表分数=新的ArrayList();
@XmlTransient
@OneToMany(mappedBy=“游戏”)
公共列表getScores(){return scores;}
公共无效设置分数(列出分数){this.scores=scores;}
}
@实体
@表(name=“\”Players\”)
公共类播放器扩展了抽象实体{
私有字符串名;
私有字符串lastname;
私人字符串电子邮件;
公共播放器(){}
@基本公共字符串getFirstname(){return firstname;}
@基本公共字符串getLastname(){return lastname;}
@基本公共字符串getEmail(){return email;}
public void setFirstname(字符串firstname){this.firstname=firstname;}
public void setLastname(字符串lastname){this.lastname=lastname;}
public void setEmail(字符串email){this.email=email;}
}
String STRRELEVENTGAMESQUERY=“从分数s中选择p,g,计数(s.Id)加入s.game g加入s.player p,其中s.scored_on=:最小游戏显示”;
TypedQuery queryRelevantGames=em.createQuery(strRelevantGamesQuery,Object[].class);
queryRelevantGames.setParameter(“minimumGamesPlayes”,5L);
setParameter(“scoredBefore”,summaryDate);
List resultreelevantGames=queryreliantGames.getResultList();
//ResultTreeLevantGames是一个对象列表[3]。所有行[0]和行[1]对象均为空,行[2]包含正确计算的计数。
//当我将查询更改为:
//String STRRELEVENTGAMESQUERY=“从中选择p.Id、g.Id、计数(s.Id)。。。
//那么所有行[0]和行[1]都包含正确的ID
p
和g
的值永远不应该是null
-您能给我们看一个示例代码吗?@MaciejDobrowolski添加了映射和查询调用。我用您的映射创建了一个项目,用示例数据填充数据库,结果数组不包含null值,请尝试升级hibernate/spring(如果使用)p
和g
的版本值永远不应该是null
-您能给我们看一个示例代码吗?@MaciejDobrowolski添加了映射和查询调用。我用您的映射创建了一个项目,用示例数据填充数据库,结果数组不包含null值,请尝试升级hibernate/spring(如果使用)版本
@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