我正在使用play框架以及JPA和Hibernate。
我有几个实体:
@Entity
public class Player extends Model {
public enum Gender {
MALE, FEMALE
}
@Required
public String name;
@Required
public Gender gender;
@Required
public Long gold;
}
@Entity
public class Building extends Model {
@Required
@ManyToOne(fetch = FetchType.LAZY)
public Player owner;
@Required
public String buildingType;
@Required
public Long buildingId;
}
@Entity
public class Stock extends Model {
// Either a product type or a raw material
@Required
public Long goodId;
@Required
public Boolean isProduct;
@Required
public String image;
}
@Entity
public class Contract extends Model {
@Required
@ManyToOne(fetch = FetchType.LAZY)
public Player player;
@Required
@ManyToOne(fetch = FetchType.LAZY)
public Building building;
@Required
@ManyToOne(fetch = FetchType.LAZY)
public Stock stock;
@Required
public Long ordersLeft;
@Required
public Long cyclesLeft;
}
通过这些实体,我想检索所有Contract
及其关联的Building
,Stock
和Player
以下是我使用的查询:
public static List<Contract> retrieveContractsForNewOrder() {
return find("select distinct c from Contract c "
+ "left join fetch c.player "
+ "left join fetch c.stock "
+ "left join fetch c.building "
+ "where c.cyclesLeft = 0 and c.ordersLeft > 0").fetch();
}
查询正常,我检索了Contract
的列表。但是,building
和stock
变量已加载但player
变量未加载(Contract
对象中的类名称为Player_$$_javassist_22
并且它具有处理程序名为JavassistLazyInitializer
)。
我不知道我做错了什么以及为什么Hibernate在获取其他模型时拒绝获取播放器模型......
感谢您的帮助
修改
经过一些测试后,hibernate执行的查询似乎是正确的:所有连接都在那里,所有模型中的所有字段都在select中。
然而结果很奇怪:我只是从Contract
和Stock
(而不是Building
和Player
)检索字段。
但我的Building
已加载,为什么?因为缓存?
为什么Building
和Player
没有出现在结果中?
编辑2
我试图在MySQL中直接执行完全相同的请求,并且我检索了我需要的所有变量,而Hibernate似乎跳过了一些变量(它们不在结果中)。
发生了什么事?
编辑3
在进行查询之前,我尝试clear()
会话缓存并猜测是什么? Player
已加载...
我尝试仅使用Player
加载left join fetch
,但它仍然无法正常工作(但由于缓存而加载了Building
)。 Player's
字段不在结果中。
但是,只要我清除了缓存,结果中就会出现Player's
字段,而Player
中会加载Contract
。
为什么清除缓存会解决问题? Player
在缓存中?如果是这样,为什么不装?
我不明白会发生什么,但我不能只清除缓存,因为我需要在此之后进行很多其他查询,我需要缓存。
答案 0 :(得分:3)
JPA强制提供程序缓存通过EntityManager读取的托管实体以维护对象标识,这样每次查询实体或在该上下文中获取对它的引用时,都会获得相同的实例。因此,如果您以尽早返回代理实例的方式读取实体,则此代理实例应保留在缓存中,直到清除EntityManager。所有后续查询都应返回该对象的同一实例。
解决方案是在关键点清除或关闭并重新获得新的EntityManager,然后确保根据需要加载对象的查询是在上下文中执行的第一个。
答案 1 :(得分:0)
尝试更改为FetchType.EAGER
答案 2 :(得分:0)
Enum in Hibernate, persisting as an enum 专注于接受的答案 对于像缓存这样的hibernate相关概念,请参阅本教程 http://www.youtube.com/playlist?list=PL4AFF701184976B25