如何获取@ElementCollection映射的相关表

时间:2016-11-23 10:29:03

标签: java hibernate jpa criteria-api

这是一个简单的产品实体,指的是一个子组:

public class Product implements Comparable<Product> {
    ...    
    @ManyToOne(optional=false, fetch=FetchType.LAZY)
    @NotNull
    private ProductSubGroup productSubGroup;
    ...
}

我在另一个实体中有一个包含Product的地图:

public class FinishedProduct {
    ...
    @NotNull
    @ManyToOne
    private Product product;

    @ElementCollection(fetch=FetchType.LAZY)
    @MapKeyJoinColumn
    @Column(name="amount")
    @Sort(type=SortType.NATURAL)
    @Fetch(FetchMode.SUBSELECT)
    private SortedMap<Product, Double> byproducts = new TreeMap<>();   
    ...
}

我可以使用以下代码加载地图:

Root<FinishedProduct> root = q.from(FinishedProduct.class);
root.fetch("product", JoinType.LEFT);
root.fetch("byproducts", JoinType.LEFT);

这样可行,但我需要存储在地图中的productSubGroup副产品,而不会生成n + 1个选择。我该怎么取他们?只需将提取添加到结尾会导致异常:

root.fetch("byproducts", JoinType.LEFT).fetch("productSubGroup", JoinType.LEFT);

org.springframework.dao.InvalidDataAccessApiUsageException: 
Collection of values [null] cannot be source of a fetch

还试图愚弄MapJoin,同样的例外:

MapJoin<FinishedProduct,Product,Double> map = root.joinMap("byproducts", JoinType.LEFT);
map.fetch("productSubGroup", JoinType.LEFT);

我想我不知何故需要参考地图键,但不知道如何。

1 个答案:

答案 0 :(得分:2)

这些是你在这里有点复杂的映射,我不确定是否有更简单的方法来实现这一点。希望有人能提供更好的答案,但作为替代方案,总有能力预先加载到持久化上下文中,您知道将使用n + 1选择获取的所有实体实例。

因此,在触发查询之前,只需加载预期要获取的所有ProductSubGroup

select p.productSubGroup from Product p
where p in (select index(byproducts) from FinishedProduct)

当然,请对原始查询中的子查询中的FinishedProduct重复任何其他限制,以避免加载您不需要的ProductSubGroup

作为更好的替代方案(在我看来),您可能需要考虑为Product.productSubGroup关联定义@BatchSize。那样ProductSubGroup将分批加载,而不是一个一个地加载。