使用 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
永远不会同时链接 FirstPossibility
和 SecondPossibility
。
存储库
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
会在代码稍后尝试访问它们时获取,并且最终也会获取 First
或 Second
实体。所有这一切,每个实体都有单独的数据库调用(从性能方面来说,这是我们想要避免的事情)。
重要说明:我们使用 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 结果(找到的每个 FirstPossibility
和 SecondPossibility
都会在结果集中创建一个条目。
如果您想改用 QueryHints.BATCH
,那么实际上需要 JOIN FETCH main.subs sub
,但您不会通过单个数据库调用返回整个结果:多个 SELECT
将发表声明。
我正在尝试使用 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
永远不会同时链接 FirstPossibility
和 SecondPossibility
。
存储库
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
会在代码稍后尝试访问它们时获取,并且最终也会获取 First
或 Second
实体。所有这一切,每个实体都有单独的数据库调用(从性能方面来说,这是我们想要避免的事情)。
重要说明:我们使用 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 结果(找到的每个 FirstPossibility
和 SecondPossibility
都会在结果集中创建一个条目。
如果您想改用 QueryHints.BATCH
,那么实际上需要 JOIN FETCH main.subs sub
,但您不会通过单个数据库调用返回整个结果:多个 SELECT
将发表声明。