【问题标题】:Fetch all relationships with JPQL使用 JPQL 获取所有关系
【发布时间】:2021-12-27 03:11:13
【问题描述】:

我正在尝试使用 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-Data 接口:

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 实体。所有这一切,对每个实体都有单独的 DB 调用(这在性能方面是我们想要避免的)。

重要提示:我们使用EclipseLink 作为我们的 JPA 提供者。

【问题讨论】:

  • 请参阅 stackoverflow.com/a/37596251/496099stackoverflow.com/a/16693590/496099 以了解 JPA/EclipseLink 中的嵌套 fetch 连接,但在通过 OneToMany 和 ManyToMany 连接时要小心父行中的内容,因为某些数据可能会导致开销超过加入的好处。例如,如果它有大量的 lobs/clob 数据,您可能希望查看批量获取,以减少网络在交叉连接这些关系时必须处理重复行。

标签: java jpa spring-data-jpa spring-data eclipselink


【解决方案1】:

感谢 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。这些重复是因为 DB 实际返回结果的方式是这样的(找到的每个 FirstPossibilitySecondPossibility 都会在结果集中创建一个条目。

如果您想改用 QueryHints.BATCH,则实际上需要 JOIN FETCH main.subs sub,但您不会通过单个 DB 调用返回整个结果:将发出多个 SELECT 语句。

【讨论】:

    猜你喜欢
    • 2020-04-10
    • 2018-02-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-28
    相关资源
    最近更新 更多