Search code examples
neo4jkotlincypherspring-data-neo4jneo4j-ogm

Neo4j spring repository can't match on related entity's Id field


I have a User which can have one or more Projects, where a BELONGS_TO relationship between the two is maintained in UserEntity which Project inherits from.

class User {
  @Id @GeneratedValue
  var id : Long?

  lateinit var name: String
}

class Project : UserEntity() {
  lateinit var title: String
}

abstract class UserEntity {
  @Id @GeneratedValue
  var id : Long?

  @Relationship(type="BELONGS_TO", type="OUTGOING")
  lateinit var user: User
}

Repositories follow a similar pattern where ProjectRepository inherits a generic fun findByIdAndUserId() from UserEntityRepository:

interface UserRepository: Neo4jRepository<T, Long> 
interface ProjectRepository: UserEntityRepository<Project>

@NoRepositoryBean
interface UserEntityRepository<T : UserEntity> : Neo4jRepository<T, Long> {
  fun findByIdAndUserId(id: Long, userId: Long): T?
}

And finally a test:

@Test
fun findByIdAndUserId() {
  // Set up
  val savedUser = userRepo.save(User(name = "John"))
  val savedProject = projectRepo.save(Project(title="Neo4j", user=savedUser))

  // Find the project
  var userProject = projectsRepo.findByIdAndUserId(savedProject.id!!, savedUser.id!!)

  // Verify projet was found
  assertThat(userProject).isNotNull() // ** FAILS **
}

So, findByIdAndUserId returns null, it doesn't find the project by project id + user id. In the logs I found this query:

MATCH (n:`Project`) 
WHERE n.`id` = {id_0}
MATCH (m0:`User`) 
WHERE m0.`id` = {user_id_1}
MATCH (n)-[:`BELONGS_TO`]->(m0) 
WITH n 
RETURN n,[ [ (n)-[r_b1:`BELONGS_TO`]->(u1:`User`) | [ r_b1, u1 ] ] ], ID(n) 
with params {id_0=2, user_id_1=1} 

Which at first seems ok because the project has id 2, and the user has id 1 (I checked neo4j), but running this query manually I also get zero results.

I found the problem is how the generated query matches User's id, it treats it as a normal property instead of an ID. It works as intended if I swap

WHERE m0.`id` = {user_id_1}

with

WHERE ID(m0) = {user_id_1}

A quick fix would be to add a findByIdAndUserId method with a custom @Query to every repository interface that inherits UserEntityRepository, but I'm hoping to avoid this duplication.

Does anyone know of a workaround for this issue? Is it a bug?


Solution

  • At the moment there is no special handling for the id field in SDN. The problem is somehow related to Spring data neo4j : count relation By EndNode ID and the resulting issue https://jira.spring.io/browse/DATAGRAPH-1049 .

    I think if this issue will get resolved SDN will have a better id handling when generating queries.