hibernate join fetch不会获取所有子项

时间:2013-08-30 14:47:56

标签: java sql hibernate jpa playframework

我正在使用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及其关联的BuildingStockPlayer

以下是我使用的查询:

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的列表。但是,buildingstock变量已加载但player变量未加载(Contract对象中的类名称为Player_$$_javassist_22并且它具有处理程序名为JavassistLazyInitializer)。

我不知道我做错了什么以及为什么Hibernate在获取其他模型时拒绝获取播放器模型......

感谢您的帮助

修改

经过一些测试后,hibernate执行的查询似乎是正确的:所有连接都在那里,所有模型中的所有字段都在select中。

然而结果很奇怪:我只是从ContractStock(而不是BuildingPlayer)检索字段。

但我的Building已加载,为什么?因为缓存? 为什么BuildingPlayer没有出现在结果中?

编辑2

我试图在MySQL中直接执行完全相同的请求,并且我检索了我需要的所有变量,而Hibernate似乎跳过了一些变量(它们不在结果中)。

发生了什么事?

编辑3

在进行查询之前,我尝试clear()会话缓存并猜测是什么? Player已加载...

我尝试仅使用Player加载left join fetch,但它仍然无法正常工作(但由于缓存而加载了Building)。 Player's字段不在结果中。 但是,只要我清除了缓存,结果中就会出现Player's字段,而Player中会加载Contract

为什么清除缓存会解决问题? Player在缓存中?如果是这样,为什么不装? 我不明白会发生什么,但我不能只清除缓存,因为我需要在此之后进行很多其他查询,我需要缓存。

3 个答案:

答案 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