因此,我编写了以下查询以在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,而不是返回多余的记录。
谢谢。
答案 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