使用 JPQL 获取所有关系

Fetch all relationships with JPQL

我正在尝试使用 JPQL 生成一个 单个 SQL 语句 来获取多个不同的实体,所有实体都链接到每个实体其他带外键。

型号

模型看起来像这样:

@Entity
@Table(name = "mainentity")
@Data
@IdClass(MainEntityPrimaryKey.class)
public class MainEntity {

    @Id
    @Column(updatable = false)
    private String foo;

    @Id
    @Column(updatable = false)
    private String bar;

    @OneToMany(cascade = {CascadeType.ALL}, orphanRemoval = true)
    @JoinColumns({
            @JoinColumn(name = "foo", referencedColumnName = "foo"),
            @JoinColumn(name = "bar", referencedColumnName = "bar")
    })
    private List<SubEntity> subs;
}
@Entity
@Table(name = "subentity")
@Data
@IdClass(SubEntityPrimaryKey.class)
public class SubEntity {

    @Id
    @Column(updatable = false)
    private String foo;

    @Id
    @Column(updatable = false)
    private String bar;

    @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true)
    @JoinColumn(name = "first_possibility_id", referencedColumnName = "first_possibility")
    private FirstPossibility firstPossibility;

    @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true)
    @JoinColumn(name = "second_possibility_id", referencedColumnName = "second_possibility")
    private SecondPossibility secondPossibility;
}
@Entity
@Table(name = "firstpossibility")
@Data
public class FirstPossibility {

    @Id
    @Column(name = "first_possibility_id", nullable = false, updatable = false)
    private String id;

    @Column
    private String something;
}
@Entity
@Table(name = "secondpossibility")
@Data
public class SecondPossibility {

    @Id
    @Column(name = "second_possibility_id", nullable = false, updatable = false)
    private String id;

    @Column
    private String stuff;
}

SubEntity 永远不会同时链接 FirstPossibilitySecondPossibility

存储库

Spring-数据接口:

public interface MainEntityCRUDRepository extends CrudRepository<MainEntity, MainEntityPrimaryKey> {

    @Query("SELECT main FROM MainEntity main WHERE CONCAT(main.foo, '~', main.bar) IN :ids")
    List<MainEntity> getAllMainWithConcatenatedIds(@Param("ids") Collection<String> ids);
}

当前状态

事实上,它在对数据库的一次调用中正确获取所有 MainEntity(我可以看到 spring.jpa.show-sql=true 属性 的绑定正确发生),但没有任意 SubEntity.

SubEntity 会在代码稍后尝试访问它们时获取,并且最终也会获取 FirstSecond 实体。所有这一切,每个实体都有单独的数据库调用(从性能方面来说,这是我们想要避免的事情)。

重要说明:我们使用 EclipseLink 作为我们的 JPA 提供程序。

感谢 Chris 的评论和帮助,我找到了这个解决方案:

public interface MainEntityCRUDRepository extends CrudRepository<MainEntity, MainEntityPrimaryKey> {

    @QueryHints({
            @QueryHint(name = org.eclipse.persistence.config.QueryHints.LEFT_FETCH, value = "main.subs.firstPossibility"),
            @QueryHint(name = org.eclipse.persistence.config.QueryHints.LEFT_FETCH, value = "main.subs.secondPossibility")
    })
    @Query("SELECT main FROM MainEntity main WHERE CONCAT(main.foo, '~', main.bar) IN :ids")
    List<MainEntity> getAllMainWithConcatenatedIds(@Param("ids") Collection<String> ids);
}

生成的 SQL 如下所示:

SELECT *
FROM mainentity t1
LEFT OUTER JOIN subentity t0 ON ((t0.foo = t1.foo) AND (t0.bar = t1.bar))
LEFT OUTER JOIN firstpossibility t2 ON (t2.id = t0.first_possibility_id)
LEFT OUTER JOIN secondpossibility t3 ON (t3.id = t0.second_possibility_id)
WHERE (t1.foo || '~' || t1.bar IN (...))

请注意 @Query 中没有 JOIN FETCH main.subs sub :已经通过 main.subs 导航的提示暗示了这一点。

如果添加 JOIN FETCH,结果 List 中实际上会有重复项。这些重复是由于这样一个事实,即数据库实际上是这样 returns 结果(找到的每个 FirstPossibilitySecondPossibility 都会在结果集中创建一个条目。

如果您想改用 QueryHints.BATCH,那么实际上需要 JOIN FETCH main.subs sub,但您不会通过单个数据库调用返回整个结果:多个 SELECT将发表声明。