JPA-如何通过连接的实体进行查询?

时间:2019-04-12 22:54:14

标签: spring jpa kotlin

因此,我编写了以下查询以在Spring JpaRespository中使用:

private const val SEARCH  =
                "SELECT vf " + 
                "FROM VideoFile vf " +
                "LEFT JOIN vf.stars st " +
                "LEFT JOIN vf.categories c " +
                "LEFT JOIN vf.series se " +
                "WHERE (:searchText IS NULL OR (" +
                "vf.fileName LIKE :searchText OR vf.displayName LIKE :searchText OR vf.description LIKE :searchText)) " +
                "AND (:seriesId IS NULL OR se.seriesId = :seriesId) " +
                "AND (:starId IS NULL OR st.starId = :starId) " +
                "AND (:categoryId IS NULL OR c.categoryId = :categoryId)"

这基于我之前测试过的SQL查询,但是编写为使用JPQL。我将在下面包括我的实体(科特琳),所以我要解释的内容会更有意义:

@Entity
@Table(name = "video_files")
data class VideoFile(
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        var fileId: Long = 0,
        @Column(unique = true)
        var fileName: String = "",
        var displayName: String = "",
        var description: String = "",
        var lastModified: LocalDateTime = DEFAULT_TIMESTAMP,
        @JsonIgnore
        var lastScanTimestamp: LocalDateTime = DEFAULT_TIMESTAMP,
        @Column(columnDefinition = "int default 0")
        var viewCount: Int = 0,

        @ManyToMany (fetch = FetchType.EAGER)
        @JoinTable(name = "file_categories",
                joinColumns = [JoinColumn(name = "file_id")],
                inverseJoinColumns = [JoinColumn(name = "category_id")])
        var categories: Set<Category> = HashSet(),

        @ManyToMany (fetch = FetchType.EAGER)
        @JoinTable(name = "file_series",
                joinColumns = [JoinColumn(name = "file_id")],
                inverseJoinColumns = [JoinColumn(name = "series_id")])
        var series: Set<Series> = HashSet(),

        @ManyToMany (fetch = FetchType.EAGER)
        @JoinTable(name = "file_stars",
                joinColumns = [JoinColumn(name = "file_id")],
                inverseJoinColumns = [JoinColumn(name = "star_id")])
        var stars: Set<Star> = HashSet()
)

因此,我的VideoFile实体与Category,Series和Star实体具有ManyToMany关系。我正在编写的查询试图获取所有与某些类别,系列,星号等相连的VideoFiles。

我现在所拥有的查询返回的是重复记录,我相信是由于LEFT JOINS的缘故。由于VideoFile与多个类别匹配,因此我得到的同一条记录多次返回。

我对SQL很好,但我仍然是JPQL的新手。我希望能有一些帮助来重构它,以便它仅按连接的实体过滤VideoFiles,而不是返回多余的记录。

谢谢。

1 个答案:

答案 0 :(得分:0)

首先,检查查询中传递的变量的“可空性”可能不是一个好主意,老实说,我不知道JPQL是否支持这种情况。

此外,由于您使用的是JPQL,因此请确保要将该查询作为JPQL查询执行,并且由于实体已经存在,因此您将不需要将其加入实体(至少不是简单的左连接)。在模型中相关。

因此您的查询应如下所示:

private const val SEARCH  =
                "SELECT vf " + 
                "FROM VideoFile vf " +
                "WHERE (vf.categories.id =:categoryId) " +
                "AND (vf.fileName LIKE :searchText OR vf.displayName LIKE :searchText OR vf.description LIKE :searchText) " +
                "AND (vf.series.id = :seriesId)  " +
                "AND (vf.stars.id = :starId) "   

只需确保类别实体中的id属性被命名为“ id”。
同样,请确保将类别中的name属性命名为“ name”,等等。

最后,您应该尝试使用null的其他方式,例如,我想您永远不需要检查实体的id属性是否为null。

因此,执行此操作的一种方法是使用StringBuilder并在Java / Kotlin级别上检查参数是否为null以及是否为null,并且还确定要获取字段的null条目,请添加一个使用OR vf.categories.name IS NULL

生成器的额外字符串