spring - spring-data-neo4j v6:找不到能够从 [MyDTO] 类型转换为 [org.neo4j.driver.Value] 类型的转换器
问题描述
情况
我正在将 kotlin spring data neo4j 应用程序从spring-data-neo4j
version迁移5.2.0.RELEASE
到 version 6.0.11
。
原始应用程序有几个带有自定义查询的 Repository 接口,这些接口将一些 DTO 作为参数,并使用各种 DTO 字段来构造查询。所有这些类型的查询目前都失败了
org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [MyDTO] to type [org.neo4j.driver.Value]
spring-data-neo4j v6的参考文档仅提供了传递给@Repository
接口的自定义查询方法的参数与与该存储库关联的类具有相同类型的示例@Node
。文档没有明确说明只允许使用 Node 类的参数。
问题
有什么方法可以将任意 DTO(不是类)传递给spring-data-neo4j v6@Node
中的接口中的自定义查询方法,就像在 v5 中一样?@Repository
代码示例
示例节点实体
@Node
data class MyEntity(
@Id
val attr1: String,
val attr2: String,
val attr3: String
)
示例 DTO
data class MyDTO(
val field1: String,
val field2: String
)
示例存储库接口
@Repository
interface MyRepository : PagingAndSortingRepository<MyEntity, String> {
// ConverterNotFoundException is thrown when this method is called
@Query("MATCH (e:MyEntity {attr1: {0}.field1}) " +
"CREATE (e)-[l:LINK]->(n:OtherEntity {attr2: {0}.field2))")
fun doSomethingWithDto(dto: MyDTO)
}
到目前为止尝试的解决方案
将 DTO 注释为 Node 实体
作为参数传递给使用自定义查询注释的函数的映射实体(带有@Node 的所有内容)将被转换为嵌套映射。
@Node
data class MyDTO(
@Id
val field1: String,
val field2: String
)
在自定义查询中替换{0}
为$0
您执行此操作的方式与在 Neo4j 浏览器或 Cypher-Shell 中发出的标准 Cypher 查询完全相同,使用 $ 语法(从 Neo4j 4.0 开始,Cypher 参数的旧 {foo} 语法已从数据库中删除)。
...
[在给定的清单中] 我们通过其名称引用参数。您也可以改用 $0 等。
@Repository
interface MyRepository : PagingAndSortingRepository<MyEntity, String> {
// ConverterNotFoundException is thrown when this method is called
@Query("MATCH (e:MyEntity {attr1: $0.field1}) " +
"CREATE (e)-[l:LINK]->(n:OtherEntity {attr2: $0.field2))")
fun doSomethingWithDto(dto: MyDTO)
}
细节
spring-boot-starter
:v2.4.10
spring-data-neo4j
:v6.0.12
neo4j-java-driver
:v4.1.4
Neo4j server version
:v3.5.29
解决方案
RTFM自定义转换...
自己找到了解决方案。希望其他人也可以从中受益。
解决方案
创建自定义转换器
import mypackage.model.*
import com.fasterxml.jackson.core.type.TypeReference
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import org.neo4j.driver.Value
import org.neo4j.driver.Values
import org.springframework.core.convert.TypeDescriptor
import org.springframework.core.convert.converter.GenericConverter
import org.springframework.core.convert.converter.GenericConverter.ConvertiblePair
import java.util.HashSet
class DtoToNeo4jValueConverter : GenericConverter {
override fun getConvertibleTypes(): Set<ConvertiblePair>? {
val convertiblePairs: MutableSet<ConvertiblePair> = HashSet()
convertiblePairs.add(ConvertiblePair(MyDTO::class.java, Value::class.java))
return convertiblePairs
}
override fun convert(source: Any?, sourceType: TypeDescriptor, targetType: TypeDescriptor?): Any? {
return if (MyDTO::class.java.isAssignableFrom(sourceType.type)) {
// generic way of converting an object into a map
val dataclassAsMap = jacksonObjectMapper().convertValue(source as MyDTO, object :
TypeReference<Map<String, Any>>() {})
Values.value(dataclassAsMap)
} else null
}
}
在配置中注册自定义转换器
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.data.neo4j.core.convert.Neo4jConversions
import org.springframework.core.convert.converter.GenericConverter
import java.util.*
@Configuration
class MyNeo4jConfig {
@Bean
override fun neo4jConversions(): Neo4jConversions? {
val additionalConverters: Set<GenericConverter?> = Collections.singleton(DtoToNeo4jValueConverter())
return Neo4jConversions(additionalConverters)
}
}
推荐阅读
- database - MongoDB 的索引是 Alternative 1 还是 Alternative 2 还是 Alternative 3?
- python - 在 pygame 中使用多处理?
- python - 如何在 MatPlotLib 中定义水平轴而不会出现弃用错误
- azure-ad-b2c - Azure B2C - 用户更改密码时自定义策略不起作用
- ios - UserInteraction 在动画视图上被禁用
- python - 具有 TensorFlow 输入的 MNIST 应该是张量
- reactjs - 如何在useEffect中返回html标签?
- javascript - 如果 IIEF 不返回内部函数,将其设置为变量的目的是什么?
- laravel - 本地服务器正确显示 yajra laravel 数据表,远程服务器给出错误 500
- python - 使用 Sympy 的矩阵导数