У меня есть следующая сущность:
@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
запросов (поиск ингредиентов).
Существуют ли лучшие / улучшенные решения?