【问题标题】:How to fetch an @ElementCollection map's related tables如何获取 @ElementCollection 映射的相关表
【发布时间】:2017-04-07 07:23:37
【问题描述】:

这是一个引用子组的简单产品实体:

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 选择。我怎样才能拿到它们?只需将 fetch 添加到最后就会导致异常:

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);

我想我需要以某种方式引用地图键,但不知道如何。

【问题讨论】:

    标签: java hibernate jpa criteria-api


    【解决方案1】:

    您在此处拥有的这些映射有点复杂,我不确定是否有更简单的方法来完成此操作。希望有人能提供更好的答案,但作为替代方案,始终可以将所有您知道将通过 n+1 选择获取的实体实例预加载到持久性上下文中。

    因此,在触发您的查询之前,只需加载所有预期会被获取的ProductSubGroups:

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

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

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

    【讨论】:

    • 两者都是有价值的建议,尽管由于某种原因我无法让@BatchSize 在这个 Spring Boot/Data/JPA/Hibernate 混乱中工作。但另一个工作,只需将@Transactional 添加到调用控制器方法。
    • 我希望将您的解决方案应用于我在stackoverflow.com/questions/40419986/… 的其他问题,但不幸的是,这有所不同,因为缓存是通过 ID 工作的,而我猜是通过另外两个 ID 进行的三向连接查询。跨度>
    • 有时我认为 Hibernate 团队中有一个人唯一的工作就是寻找现实生活中的使用场景并使其成为不可能。 :)
    • 与任何框架一样,缺少一些可能有用的功能(例如与可能与您的其他问题相关的非关联实体的外部连接),以及一些起初可能看起来不直观的东西一眼。习惯 ORM 概念需要时间。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-06
    • 2018-09-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多