Как выбрать атрибут @ElementCollection с данными JPA Spring? - PullRequest
0 голосов
/ 24 августа 2018

У меня есть следующая сущность:

@Entity
data class PieEntity(
        @get:Column
        var name: String = "name",

        @get:Enumerated(EnumType.STRING)
        @get:ElementCollection
        var ingredients: MutableSet<PieIngredient> = mutableSetOf(PieIngredient.A, PieIngredient.B),

        // lots of other properties...

        @get:Id
        @get:GeneratedValue
        var id: Long? = null)

enum class PieIngredient { A, B, C }

Теперь я хотел бы выбрать только подмножество его атрибутов, в данном случае атрибуты name и ingredients.

В настоящее время я нашел 4 возможных решения, но все они имеют недостатки:

Решение 1

Использовать проекцию на основе классов:

data class PiePreviewDto(
    val name: String,
    val ingredients: PieIngredient)

@Repository
interface PieRepository : JpaRepository<PieEntity, Long> {
    fun findTop3ByOrderByNameDesc(): List<PiePreviewDto>
}

Это создает оператор выбора, который выбирает только нужные атрибуты.

Проблема здесь в том, что я получаю один результат за пирог на ингредиент. Например, если у меня есть 2 пирога с 2 ингредиентами в каждом, я получаю 4 результата, что означает, что мне нужно объединить эти результаты вручную, что кажется нежелательным.

Решение 2

Использовать проекцию:

interface PiePreview {
    val name: String
    val ingredients: MutableSet<PieIngredient>
}

@Repository
interface PieRepository : JpaRepository<PieEntity, Long> {
    fun findTop3ByOrderByNameDesc(): List<PiePreview>
}

Здесь я получаю один результат за пирог (что хорошо).

Проблема в том, что он на самом деле выбирает все атрибуты, и у меня есть некоторые "сгустки", которые я не хочу выбирать (таким образом, именно этот вопрос).

Раствор 3

Используйте переплетение байт-кода, чтобы я мог лениво извлекать все (даже @Basic свойства).

Я не пробовал это, так как это, кажется, зависит от поставщика. Однако я хочу попробовать, если это наиболее разумное решение.

Решение 4

Дублирующиеся атрибуты с конвертерами и проекцией на основе классов:

@Entity
data class PieEntity(
        @get:Column
        var name: String = "name",

        @get:Convert(converter = PieIngredientSetConverter::class)
        var ingredients: MutableSet<PieIngredient> = mutableSetOf(A, B),

        @get:Enumerated(EnumType.STRING)
        @get:ElementCollection
        var ingredientSet: MutableSet<PieIngredient> = mutableSetOf(A, B),

        // lots of other properties...

        @get:Id
        @get:GeneratedValue
        var id: Long? = null)

class PieIngredientSetConverter : AttributeConverter<MutableSet<PieIngredient>, String> {
    override fun convertToDatabaseColumn(attribute: MutableSet<PieIngredient>) =
            attribute.joinToString(",") { it.name }

    override fun convertToEntityAttribute(dbData: String) =
            dbData.split(PATTERN).map { PieIngredient.valueOf(it) }.toMutableSet()
}

data class PiePreviewDto(
    val name: String,
    val ingredients: MutableSet<PieIngredient>)

@Repository
interface PieRepository : JpaRepository<PieEntity, Long> {
    fun findTop3ByOrderByNameDesc(): List<PiePreviewDto>
}

Выбирает только те атрибуты, которые мне нужны.

Проблема в том, что мне приходится вручную синхронизировать дублирующиеся атрибуты, он занимает больше места на диске (в моем случае это не проблема) и его необходимо преобразовать.

Мне нужен атрибут ingredientSet, поскольку я выполняю IN запросов (поиск ингредиентов).


Существуют ли лучшие / улучшенные решения?

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