我有一些用于过滤查询数据的内联函数,如下所示:
inline fun <reified T> findByFilterFunc(filter: String, em: EntityManager, offset: Int, limit: Int, sortName: String?, sortDirection: String?): List<T> {
val bt = SimpleBuilderTools()
val rootNode = RSQLParser().parse(filter)
val builder = em.criteriaBuilder
val query = initQueryFunc<T, T>(builder, filter)
val root = query.getRootByType(T::class.java)
query.where(PredicateBuilderObj.createPredicate(rootNode, em, bt, root, query))
query.select(root)
if (sortName !== null) {
val expression = root.get<Expression<*>>(sortName)
query.orderBy(if (sortDirection == "ASC") builder.asc(expression) else builder.desc(expression))
}
return em.createQuery(query).setFirstResult(offset * limit).setMaxResults(limit).resultList
}
但是我可以在 SQL 查询中使用排序,因为我的方言不支持它。我尝试使用 kotlin
sortedBy {}
来查询结果,如下所示:
val prop = T::class.java.javaClass.kotlin.declaredMemberProperties.find { it.name == sortName }
return em.createQuery(query).setFirstResult(offset * limit).setMaxResults(limit).resultList.sortedBy(prop)
但是这是无效代码。如何对具有泛型类型的集合进行排序?
我认为我需要使用自定义比较器,但我不明白如何对未知的泛型类型执行此操作
TL;DR 我认为 Kotlin 没有足够的信息来实现未知类型的比较
T
。
以下是对您的代码的一些更改:
首先你有
val prop = T::class.java.javaClass.kotlin.declaredMemberProperties.find { it.name == sortName }
返回
KProperty1<Class<T>, *>?
我想你需要这个:
val prop: KProperty1<T, *>? = T::class.declaredMemberProperties.find { it.name == sortName }
然后就可以获取属性的运行时值了:
requireNotNull(prop)
prop.get(...instance...)
然后你实现一个像这样的内联自定义比较器
return em.createQuery(query)
.setFirstResult(offset * limit)
.setMaxResults(limit)
.resultList
.sortedWith { o1: T, o2: T ->
val v1: Any? = prop.get(o1)
val v2: Any? = prop.get(o2)
//how to compare?
v1.toString().compareTo(v2.toString())
}
问题是类型信息不可用,并且由于
Any
未实现compareTo
你如何知道一般如何排序?
您可能会问自己的问题...数据库引擎如何排序?如果它是具有强类型列的 RDMS,则引擎在运行时知道要使用什么排序/排序规则。如果它是非结构化存储,例如 Mongo,它有一个策略来对它支持的相对较少类型进行排序。
您将在您的应用程序中提供多少种类型的排序?一旦您知道运行时类型,并且如果您要使用此实用程序的类型数量有限,我想您可以编写自定义比较器(
if v1 is Number
,然后您就会知道该怎么做)或回退到toString().compareTo
但是,如果您可以首先对
T
施加更严格的约束...它必须像这样实现 Comparable
:
inline fun <reified T : Comparable<T>> findByFilterFunc(...
然后你就可以写了
.sortedWith { o1: T, o2: T ->
val v1 = prop.get(o1) as T
val v2 = prop.get(o2) as T
v1.compareTo(v2)
}