Jpa规范查找字段值的子集

时间:2017-09-05 20:37:20

标签: java jpa java-ee spring-data-jpa kotlin

我正在使用Spring Data JPA在持久层上编写一个webapp,更具体地说,我的DAO扩展了JpaSpecificationExecutor接口,因此我能够实现某种过滤器;想象具有多个属性的Item列表(为了清楚起见,我省略了注释和其他元数据):

data class Item(var tags: MutableList<String>)

在我的服务图层上,我的过滤方法如下所示:

fun findBy(tagsToFilterBy: List<String>): List<Items> {
    return dao.findAll { root, query, builder ->
        builder.//??
    }
}

我想要实现的只是检索仅包含Item的{​​{1}},换句话说,tagsToFilterBy应该是tagsToFilterBy的子集。

我知道Item.tags方法,但我认为它的使用对于很多标签来说并不是很愉快,因为它在接听时只接受单个“实体”。你能给我一些建议吗?

我的另一个问题是,是否可以直接使用用户输入,例如isMember(...),或者我必须将其放在builder.like(someExpression, inputFromUser)然后builder.parameter(...)

感谢您的任何想法

2 个答案:

答案 0 :(得分:0)

一种方法是使用过滤器并测试每个元素,看看你的过滤器列表是否包含它。

val result = dao.filter { tagsToFilterBy.contains(it.tag) }

要加快速度,您可以强制对筛选器列表进行排序,也可以使用binarySearch,但性能提升(或不提高)取决于筛选器列表的大小。例如,假设tagsToFilterBy已排序,则:

val result2 = dao.filter { tagsToFilterBy.binarySearch(it.tag) >= 0 }

Kotlin Collection页面描述了这些扩展方法。

答案 1 :(得分:0)

所以我设法自己写。我不是说它很漂亮,但它是最漂亮的,我可以带来:

dao.findAll { root, query, builder ->
    val lst = mutableListOf<Predicate>()
    val tagsPath = root.get<List<Tag>>("tags")
    tagsToFilterBy.forEach {
        lst.add(cb.isMember(it, tagsPath))
    }
    cb.or(*lst.toTypedArray())
}

这基本上是通过给定的标签,并检查它是否是标签的成员。