JPA - Как сделать запрос по объединенным объектам? - PullRequest
0 голосов
/ 13 апреля 2019

Итак, я написал следующий запрос для использования в 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. Я собираюсь включить мою сущность (Kotlin) ниже, так что то, что я собираюсь объяснить, будет иметь больше смысла:

@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 имеет отношение ManyToMany с сущностями Category, Series и Star. Запрос, который я пишу, является попыткой получить все видеофайлы, объединенные с определенными категориями, сериями, звездами и т. Д.

Запрос, который у меня сейчас есть, возвращает дубликаты записей, я полагаю, из-за левых соединений. Поскольку видеофайл совпадает с несколькими категориями, одна и та же запись возвращается несколько раз.

Я хорошо разбираюсь в SQL, я все еще новичок в JPQL. Я был бы признателен за помощь в рефакторинге, чтобы он просто фильтровал видеофайлы по объединенным объектам, а не возвращал дополнительные записи.

Спасибо.

1 Ответ

0 голосов
/ 13 апреля 2019

Прежде всего, проверка на «обнуляемость» переданной переменной внутри запроса, вероятно, не очень хорошая идея, и, честно говоря, я не знаю, поддерживает ли 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в категориях с именем "имя" и т. д ... вы поняли.

Наконец, вы должны попробовать другой подход с нулевыми значениями, например, я думаю, вам никогда не понадобится проверять свойство id объекта на нулевые значения.

Итак, один из способов сделать это - использовать StringBuilder и проверить на уровне Java / Kotlin, если параметр имеет значение null и если он есть, а также вы уверены, что хотите получить нулевые записи поля,Вы добавляете дополнительную строку в конструктор с помощью OR vf.categories.name IS NULL

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...