我有以下实体:
@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 }
现在我只想选择其属性的一个子集,在本例中为nameandingredients属性。
目前我找到了 4 种可能的解决方案,但它们都有缺陷:
解决方案 1
使用基于类的投影:
data class PiePreviewDto(
val name: String,
val ingredients: PieIngredient)
@Repository
interface PieRepository : JpaRepository<PieEntity, Long> {
fun findTop3ByOrderByNameDesc(): List<PiePreviewDto>
}
这将创建一个仅选择所需属性的 select 语句。
这里的问题是我得到每个馅饼每种成分的一个结果。例如,如果我有 2 个馅饼,每个馅饼有 2 种成分,我会得到 4 个结果,这意味着我必须手动合并这些结果,这似乎是不可取的。
解决方案 2
使用投影:
interface PiePreview {
val name: String
val ingredients: MutableSet<PieIngredient>
}
@Repository
interface PieRepository : JpaRepository<PieEntity, Long> {
fun findTop3ByOrderByNameDesc(): List<PiePreview>
}
在这里,每个派我得到一个结果(这很好)。
问题是它实际上选择了所有属性,并且我有一些我不想选择的“lob”(因此正是这个问题)。
解决方案 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查询(搜索成分)。
有更好/改进的解决方案吗?