Skip to content

Add association support for DTO projections #2305

Closed
@pelletier197

Description

@pelletier197

Given I have an entity that has a single relationship to another entity. If I want to have a projection of that entity with a nullable related entity, the request fails.

interface TestPersonRepository : Neo4jRepository<PersonEntity, String> {
    @Query("""
        MATCH (person:Person) 
        OPTIONAL MATCH (person)-[:WORKS_IN]->(department:Department)
        return person, department
    """)
    fun findPeopleWithDepartments() : List<PersonProjection>
}

data class PersonProjection(
    val person: PersonEntity,
    val department: DepartmentEntity?
)

@Service
class TestService(
    private val repository: TestPersonRepository
)
{
    init {
            val results = repository.findPeopleWithDepartments() // Throws exception
            println(results) 
    }
}

I actually saw a related issue that is marked as resolved, but I think the null use-case was forgotten in 6.1.2: #2269

The stacktrace I get is

Caused by: org.neo4j.driver.exceptions.value.NotMultiValued: NULL is not iterable
	at org.neo4j.driver.internal.value.ValueAdapter.values(ValueAdapter.java:401)
	at org.neo4j.driver.internal.value.ValueAdapter.values(ValueAdapter.java:395)
	at org.springframework.data.neo4j.core.mapping.DefaultNeo4jEntityConverter.determineQueryRoot(DefaultNeo4jEntityConverter.java:127)
	at org.springframework.data.neo4j.core.mapping.DefaultNeo4jEntityConverter.read(DefaultNeo4jEntityConverter.java:102)
	at org.springframework.data.neo4j.core.mapping.DefaultNeo4jEntityConverter.read(DefaultNeo4jEntityConverter.java:67)
	at org.springframework.data.neo4j.core.mapping.DtoInstantiatingConverter.lambda$getPropertyValueFor$4(DtoInstantiatingConverter.java:160)
	at org.springframework.data.neo4j.core.mapping.DtoInstantiatingConverter.getPropertyValueFor(DtoInstantiatingConverter.java:173)
	at org.springframework.data.neo4j.core.mapping.DtoInstantiatingConverter$1.getParameterValue(DtoInstantiatingConverter.java:102)
	at org.springframework.data.mapping.model.ClassGeneratingEntityInstantiator.extractInvocationArguments(ClassGeneratingEntityInstantiator.java:269)

The source of this is in DefaultNeo4jEntityConverter.

Iterable<Value> recordValues = mapAccessor instanceof Value && ((Value) mapAccessor).hasType(nodeType) ?
		Collections.singletonList((Value) mapAccessor) : mapAccessor.values(); // <-- this last part throws when the single entity result is null, since the mapAccessor is a `NullValue`.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions