使用带Statement参数的ReactiveNeo4jTemplate findAll方法返回空结果
问题:ReactiveNeo4jTemplate带Statement参数的findAll方法返回空结果,导致updateAll失效
使用ReactiveNeo4jTemplate的findAll方法并传入Statement参数时,数据库中存在匹配该Statement的节点,但方法返回空结果。其他模板方法均可正常工作,仅此方法异常。
测试用例需要更新符合特定条件的所有元素,但由于带Statement的findAll无返回值,更新逻辑未执行;而不带查询条件的findAll方法可正常获取所有元素。
相关代码实现
Neo4jQueryableRepositoryAdapter类
class Neo4jQueryableRepositoryAdapter<T : Any, ID : Any>( private val delegator: Neo4jRepository<T, ID>, clazz: KClass<T> ) : QueryableRepository<T, ID>, Repository<T, ID> by delegator { private val parser = Neo4jCriteriaParser(clazz) // 更多代码和函数 override fun updateAll( criteria: Criteria, patch: Patch<T>, limit: Int?, offset: Long?, sort: Sort? ): Flow<T> { return parser.parse(criteria).let { delegator.updateAll(it, patch, limit, offset, sort) } } // 更多代码和函数 }
SimpleNeo4jRepository类
@Suppress("UNCHECKED_CAST") class SimpleNeo4jRepository<T : Any, ID : Any>( private var template: ReactiveNeo4jTemplate, val clazz: KClass<T>, eventPublisher: EventPublisher? = null, ) : Neo4jRepository<T, ID> { // 更多代码和函数 override fun updateAll( criteria: Statement, patch: Patch<T>, limit: Int?, offset: Long?, sort: Sort? ): Flow<T> { return updateAll(criteria, patch.async(), limit, offset, sort) } override fun updateAll( criteria: Statement, patch: SuspendPatch<T>, limit: Int?, offset: Long?, sort: Sort? ): Flow<T> { return findAll(criteria, limit, offset, sort) .map { update(it, patch) } .filterNotNull() } override fun findAll(criteria: Statement?, limit: Int?, offset: Long?, sort: Sort?): Flow<T> { // 验证limit和offset val l = limit ?: Int.MAX_VALUE val o = offset ?: 0 // 若指定条件则执行自定义查询 val all = if (criteria != null) { println("QUERY ➡️ ${criteria.cypher}") template.findAll(criteria, clazz.java) } else { template.findAll(clazz.java) }.subscribeOn(Schedulers.parallel()) .asFlow() // 应用limit和offset并返回结果 return all.drop(o.toInt()).take(l) } // 更多代码和函数 }
Neo4j配置类
import com.astrum.data.annotation.ConverterScope import org.neo4j.driver.AuthTokens import org.neo4j.driver.Driver import org.neo4j.driver.GraphDatabase import org.springframework.context.ApplicationContext import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import org.springframework.core.convert.converter.GenericConverter import org.springframework.core.env.Environment import org.springframework.data.convert.ReadingConverter import org.springframework.data.convert.WritingConverter import org.springframework.data.neo4j.config.AbstractReactiveNeo4jConfig import org.springframework.data.neo4j.core.convert.Neo4jConversions import org.springframework.data.neo4j.repository.config.EnableReactiveNeo4jRepositories import org.springframework.transaction.annotation.EnableTransactionManagement @Configuration @EnableReactiveNeo4jRepositories("com.astrum") @EnableTransactionManagement class Neo4jConfiguration( private val applicationContext: ApplicationContext, private val env: Environment ) : AbstractReactiveNeo4jConfig() { @Bean override fun neo4jConversions(): Neo4jConversions { val converters = applicationContext.getBeansOfType(GenericConverter::class.java) .values .filter { it.javaClass.annotations.any { annotation -> annotation is WritingConverter || annotation is ReadingConverter } } .filter { val scope = it.javaClass.annotations.filterIsInstance<ConverterScope>() scope.isEmpty() || scope.any { converterScope -> converterScope.type == ConverterScope.Type.NEO4J } } return Neo4jConversions(converters) } /** * 用于与Neo4j交互的驱动。 * * @return 要使用的Neo4j Java驱动实例。 */ @Bean override fun driver(): Driver { val uri = env.getProperty("spring.data.neo4j.uri") ?: "bolt://localhost:7687" val username = env.getProperty("spring.data.neo4j.username") ?: "neo4j" val password = env.getProperty("spring.data.neo4j.password") ?: "password" return GraphDatabase.driver(uri, AuthTokens.basic(username, password)) } }
测试代码
@Test fun updateAllByName() = parameterized { personRepository -> val person = DummyPerson.create() .let { personRepository.create(it) } val patch = DummyPerson.create() // 用于验证 var all = personRepository.findAll(where(Person::name).`is`(person.name)).toList() println("all persons ✅: $all") val updatedPersons = personRepository.updateAll( where(Person::name).`is`(person.name), Patch.with { it.name = patch.name it.age = patch.age } ).toList() // 用于验证 all = personRepository.findAll(where(Person::name).`is`(person.name)).toList() println("all persons ❌: $all") assertEquals(1, updatedPersons.size) val updatedPerson = updatedPersons[0] assertEquals(person.id, updatedPerson.id) assertEquals(patch.name, updatedPerson.name) assertEquals(patch.age, updatedPerson.age) assertNotNull(updatedPerson.updatedAt) }
测试执行结果
- 直接调用带Criteria的
findAll能获取到节点:all persons ✅: [Person(name=arletha.dietric, age=67)] - updateAll内部执行的Cypher语句为:
QUERY ➡️ MATCH (n:Person) WHERE n.name = 'arletha.dietric' RETURN n - 更新后查询节点未改变:
all persons ❌: [Person(name=arletha.dietric, age=67)] - 测试因
updatedPersons长度为0而失败
内容的提问来源于stack exchange,提问作者Yuniel Acosta Pérez
相关产品推荐
相关产品推荐

