我有一个问题,一个非常简单的选择(SELECT h FROM Hero h,其中h.owner =:player)会导致n + 1问题。该查询触发每个英雄实体对游戏的选择。
首先我添加了fetch类型lazy,它在select期间删除了替代查询。在我的代码中,我只需要一次游戏即可获得id。这为每个实体再次触发了选择。
所以我添加了一个帮助的连接提取,但它导致了我不需要的连接!我怎么能告诉hibernate代理对象在没有获取整个实体的情况下给我id?
我尝试了那里的提示但没有成功:http://256stuff.com/gray/docs/misc/hibernate_lazy_field_access_annotations.shtml
来自hibernate的@AccessType和来自javax的@Access都没有区别。当我调用getId()时,将始终获取游戏。
任何想法我错过了什么?我经常需要这个,如果可以,我想避免加入。
问候, 马库斯
PS:我使用jpa2 + hibernate 4和jboss 7。
@Entity
@NamedQueries({
@NamedQuery(name = "Hero.findByPlayer", query = "SELECT h FROM Hero h JOIN FETCH h.game where h.owner = :player")
})
public class Hero extends GameCharacter implements Serializable {
@ManyToOne
private Player owner;
@Entity
public abstract class GameCharacter extends GameObject implements Serializable {
... nothing special in here
}
@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
public abstract class GameObject implements Serializable {
@Id
private String id = java.util.UUID.randomUUID().toString();
@ManyToOne(fetch=FetchType.LAZY)
protected Game game;
@Entity
public class Game implements Serializable {
private static final long serialVersionUID = 4379242677193301727L;
@Id
private String id = java.util.UUID.randomUUID().toString();
答案 0 :(得分:1)
这只是hibernate中延迟加载方式的一个副作用。从本质上讲,对惰性对象的任何访问都会导致它被填充。它不是id的特殊情况。
我认为你实际上无法在不触发加载的情况下从游戏对象中访问ID。你可以做的是使用getIdentifier方法向hibernate询问对象的id。我相信这不会触发获取,因为hibernate只是查找它对象的元数据。
或者,您可以在执行查询时在英雄身边加载游戏ID。
E.g。
SELECT h, h.game.id FROM Hero h where h.owner = :player
不是在当前查询中找到你的英雄列表,而是返回一对对象列表,每对都有英雄和游戏ID。
ID在HQL中被特别处理,因此在尝试访问对象时不会触发您获取的提取或连接。