Spring 数据 Neo4j - ORDER BY {order} 失败

Spring Data Neo4j - ORDER BY {order} fails

我有一个查询,结果应根据传递的参数排序:

@Query("""MATCH (u:User {userId:{uid}})-[:KNOWS]-(:User)-[h:HAS_STUFF]->(s:Stuff)
    WITH s, count(h) as count ORDER BY count {order}
    RETURN o, count SKIP {skip} LIMIT {limit}""")
        fun findFromOthersByUserIdAndSortByAmountOfStuff(
         @Param("uid") userId: String,
         @Param("skip") skip: Int,
         @Param("limit") limit: Int,
         @Param("order) order: String): List<StuffWithCountResult>

对于 order 参数,我使用以下 enum 及其唯一方法:

enum class SortOrder {
    ASC,
    DESC;
    fun toNeo4JSortOrder(): String {
        when(this) {
            ASC -> return ""
            DESC -> return "DESC"
        }
    } 
 }

好像SDN没有正确处理{order}参数?在执行时,我得到一个异常告诉

 Caused by: org.neo4j.kernel.impl.query.QueryExecutionKernelException: Invalid input 'R': expected whitespace, comment or a relationship pattern (line 3, column 5 (offset: 244))
 "    RETURN o, count SKIP {skip} LIMIT {limit}"
      ^

如果我从 Cypher 语句中删除参数或将其替换为硬编码 DESC,则该方法会成功。我相信这不是因为 enum 因为我在其他存储库方法中使用(其他)枚举并且所有这些方法都成功了。我已经尝试过不同的参数命名方式,例如 sortOrder,但这没有帮助。

我在这里错过了什么?

这是更改 排序分页 信息的错误模型。您可以跳到下面的答案以了解如何使用这些选项,或者继续阅读以了解您的代码目前存在的问题。

您不能在不允许绑定的地方绑定:

您不能将参数绑定到未为 "parameter binding" 设置的查询语法元素中。参数绑定不进行简单的字符串替换(因为您可能会受到注入攻击),而是使用绑定 API 来绑定参数。您正在处理查询注释,就像它正在执行字符串替换一样,但事实并非如此。

parameter binding docs for Neo4J and the Java manual for Query Parameters 准确显示您可以绑定的位置,唯一允许的位置是:

  • 代替字符串文字
  • 代替正则表达式
  • 字符串模式匹配
  • 创建具有属性的节点,作为属性
  • 创建多个具有属性的节点,作为属性
  • 设置节点的所有属性
  • SKIP 和 LIMIT 的数值
  • 作为节点 ID
  • 作为多个节点 ID
  • 索引值
  • 索引查询

在 ORDER BY 子句中没有任何内容表明您正在尝试的内容是允许的。

这并不是说 Spring Data 的作者无法解决这个问题并允许在其他地方进行绑定,但看起来他们所做的并不比 Neo4J Java API 允许。

您可以改为使用排序 class:

针对版本 4.2.0.M1 标记了允许此操作的修复,该版本是截至 2016 年 9 月 8 日的预发布版,请参阅下文了解使用里程碑版本

Spring 数据有一个 Sort class,如果你的 @Query 注释方法有一个这种类型的参数,它应该应用排序并允许动态修改查询。

我假设代码看起来像(未经测试):

@Query("MATCH (movie:Movie {title={0}})<-[:ACTS_IN]-(actor) RETURN actor")
List<Actor> getActorsThatActInMovieFromTitle(String movieTitle, Sort sort);

或者您可以使用 PageRequest class / Pageable 接口:

针对版本 4.2.0.M1 标记了允许此操作的修复,该版本是截至 2016 年 9 月 8 日的预发布版,请参阅下文了解使用里程碑版本

在当前 Spring Data + Neo4j docs 中,您会看到使用分页的示例:

@Query("MATCH (movie:Movie {title={0}})<-[:ACTS_IN]-(actor) RETURN actor")
Page<Actor> getActorsThatActInMovieFromTitle(String movieTitle, PageRequest page);

(Spring 数据中 Cypher Examples 的样本 + Neo4j 文档)

而这个 PageRequest class also allows sorting parameterization. Anything that implements Pageable 也会做同样的事情。使用 Pageable 可能更合适:

@Query("MATCH (movie:Movie {title={0}})<-[:ACTS_IN]-(actor) RETURN actor")
Page<Actor> getActorsThatActInMovieFromTitle(String movieTitle, Pageable page);

您或许可以在早期版本中使用 SpEL:

作为替代方案,您可以查看 using SpEL expressions 以在查询的其他区域进行替换。我不熟悉它,但它说:

Since this mechanism exposes special parameter types like Sort or Pageable as well, we’re now able to use pagination in native queries.

但是official docs好像说比较有限

你应该知道的其他信息:

有人在 GitHub issue. Which then leads to DATAGRAPH-653 issue which was marked as fixed in version 4.2.0.M1. This references other SO questions here which are outdated so you should ignore those like 中报告了与您完全相同的问题,但已不再正确。

查找 Spring 数据 Neo4j 里程碑构建:

您可以在项目页面上查看 dependencies information for any release。对于 4.2.0.M1 构建 Gradle 的信息(您可以推断 Maven)是:

dependencies {
    compile 'org.springframework.data:spring-data-neo4j:4.2.0.M1'
}

repositories {
    maven {
        url 'https://repo.spring.io/libs-milestone'
    }
}

应改用任何较新的最终版本。