Reputation: 1
I’m working with Spring 3.3.2 and Spring Data Neo4j 7.3.2. I have a repository that looks like this:
@Query("MATCH p=allShortestPaths((rootNode:SoftwareComponent {softwareComponent:${"$"}softwareComponent , version:${"$"}version })-[:DEPENDS_ON_SOFTWARE_COMPONENT *1..15]->(dependentNode:SoftwareComponent)) " +
"WHERE rootNode <> dependentNode " +
"WITH rootNode AS __sn__, collect(distinct (relationships(p))) AS __sr__, collect(distinct (dependentNode)) AS __srn__ " +
"RETURN __sn__, __sr__, __srn__")
fun findDependencyByVersion(
@Param("softwareComponent") softwareComponent: String, @Param("version") version: String
): List<SoftwareComponent>
And I am using the following Node definition:
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator::class, property = "id")
@Node("SoftwareComponent")
class SoftwareComponent(
@Property(name = "softwareComponent") var softwareComponent: String,
@Property(name = "version") var version: String,
@Relationship(type = "DEPENDS_ON_SOFTWARE_COMPONENT", direction = Relationship.Direction.OUTGOING)
@JsonManagedReference
var dependencies: HashSet<DependsOnSoftwareComponent> = HashSet(),
@Id @GeneratedValue var id: Long? = null
)
I am now trying to create another repository to fetch the reverse dependencies (the "consumers") of my SoftwareComponent, i.e., the nodes that depend on my current node. Here is the query I am trying to use:
@Query("MATCH p=(rootNode:SoftwareComponent {softwareComponent: ${"$"}softwareComponent, version: ${"$"}version})<-[r:DEPENDS_ON_SOFTWARE_COMPONENT *0..6]-(s:SoftwareComponent) " +
"WITH rootNode AS __sn__, collect (relationships(p)) AS __sr__ , collect (nodes(p)) AS __srn__ " +
"RETURN __sn__, __sr__, __srn__")
fun findConsumerByVersion(
@Param("softwareComponent") softwareComponent: String, @Param("version") version: String
): List<SoftwareComponent>
The issue I am facing is:
Caused by: org.springframework.data.mapping.MappingException: The node with id 2887 has a logical cyclic mapping dependency; its creation caused the creation of another node that has a reference to this.
So my question is: How can I configure Spring Data Neo4j to handle bidirectional relationships without creating cyclic dependencies or duplicating the primary label?
Upvotes: 0
Views: 49
Reputation: 8262
There are two ways this could be meant:
I end up with cyclic dependencies that make the application impossible to load
Similar to the problem/answer when rendering the result with JSON at the bottom, your domain is defined as sth. like SoftwareComponent
->SoftwareComponent
->Software...
but also contains constructor dependencies in a way similar to
public SoftwareComponent(Software software) {}
/...
public Sofware(SoftwareComponent component) {}
When SDN tries to map this, it will follow the data. And if it finds a cycle, it will also follow this and eventually end in the
Caused by: org.springframework.data.mapping.MappingException: The node with id 2887 has a logical cyclic mapping dependency;
In those cases, you have to break this cycle by either defining a setter or wither in one of those entities. (Examples can be found here: https://docs.spring.io/spring-data/neo4j/reference/object-mapping/sdc-object-mapping.html#mapping.fundamentals.property-population)
The only downside of this is, that you cannot make the property final
anymore.
(Edit: previous assumptions and solutions)
As you have already experienced, defining the bidirectional dependency in the database could lead to unexpected performance drops because with a highly connected graph, SDN will fetch "everything" that is reachable.
For your situation, there is a projection feature in place, that allows you to define interfaces that only reflect a sub-set of the defined global model.
This is due to the fact that Jackson will chase every reachable field and SoftwareComponent
->SoftwareComponent
->Software...
is an infinite self-referencing loop. To break out of this, the mentioned answer I gave about the use of Jackson (thanks @cybersam for finding this link already) is still valid.
To free
Upvotes: 1