Skip to content

Target of relationship property entities is serialised into properties and not as a separate property. #2537

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
venkat125 opened this issue May 11, 2022 · 4 comments
Assignees
Labels
type: bug A general bug

Comments

@venkat125
Copy link

venkat125 commented May 11, 2022

__properties__ is the map entry that will always point to the properties of an entity, __id__ will always point to the @Id column and __target__, well to the @Target.

Please take a look on test case. Below is the follow up of the reference test case.

nid is custom id not the neo4j internal id

case 1 :

It updates department and age property in Person Entity, but not updating relationships between person and languages. Thus returning empty / null like in original post. (knows) arraylist of relationship is not serialized it seems.

@Query("MATCH (m:Person {nid: $personObj.__id__}) WITH m " +
            "SET m.department = $personObj.__properties__.department , m.age = $personObj.__properties__.age WITH m " +
            "UNWIND $personObj.__properties__.__knows__ AS obj " +
            "CALL apoc.do.when(obj.__properties__.to_delete," +
                "'MATCH (m)-[cr:KNOWS]->(l:Language {name: o.__properties__.__target__.__id__}) DELETE cr RETURN m'," +
                "'OPTIONAL MATCH (l:Language {name: o.__properties__.__target__.__id__}) " +
                    "MERGE (m)-[cr:KNOWS]->(l) " +
                        "ON MATCH SET " + LANGUAGE_PROPS +
                        "ON CREATE SET " + LANGUAGE_PROPS + " RETURN m,cr,l'," +
                "{m:m, o:obj}) YIELD value " +
            "RETURN m, collect(value.cr), collect(value.l)")
Person updatePersonInfoRepo(@Param("personObj") Person person);

Case 2 :

But, it works fine when passed collection and first level property separately in parameters like below (updates the DB)

@Query("MATCH (m:Person {nid: $personObj.__id__}) WITH m " +
        "SET m.department = $personObj.__properties__.department, m.age = $personObj.__properties__.age WITH m " +
        "UNWIND $relations AS obj " +
        "CALL apoc.do.when(obj.__properties__.to_delete," +
            "'MATCH (m)-[cr:KNOWS]->(l:Language {name: o.__properties__.__target__.__id__}) DELETE cr RETURN m'," +
            "'OPTIONAL MATCH (l:Language {name: o.__properties__.__target__.__id__}) " +
                "MERGE (m)-[cr:KNOWS]->(l) " +
                    "ON MATCH SET cr.speak = o.__properties__.speak, cr.read = o.__properties__.read " +
                    "ON CREATE SET cr.speak = o.__properties__.speak, cr.read = o.__properties__.read RETURN m,cr,l'," +
            "{m:m, o:obj}) YIELD value " +
        "RETURN m, collect(value.cr), collect(value.l)")
Person updatePersonInfoRepo(@Param("personObj") Person person, @Param("relations") Set<Knows> relation);

Seems the collection property inside the Entity is not getting serialized or not accessible. but other first level properties are accessible in query.
Note: spring-boot-starter-data-neo4j version: 2.6.7 used
Is there a way to use the Person Entity alone to construct whole query?

Originally posted by @michael-simons in #2292 (comment)

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label May 11, 2022
@michael-simons
Copy link
Collaborator

Thanks for the feedback @venkat125

They are actually serialized but not into the correct bucket. Will be fixed, and you'll find an example in the linked test class

@michael-simons michael-simons changed the title Collection property in Entity as @param is not serialized it seems but other first level props in entity does Target of relationship entity properties is serialised into properties and not as a separate property. May 12, 2022
@michael-simons michael-simons self-assigned this May 12, 2022
@michael-simons michael-simons added type: bug A general bug and removed status: waiting-for-triage An issue we've not yet triaged labels May 12, 2022
@michael-simons
Copy link
Collaborator

I also changed the title: The target entity is in fact not correctly serialised, the properties are. I didn't run you code because APOC and also I don't have time to debug the query, but things on the properties side are working correctly.

@michael-simons michael-simons changed the title Target of relationship entity properties is serialised into properties and not as a separate property. Target of relationship property entities is serialised into properties and not as a separate property. May 12, 2022
michael-simons added a commit that referenced this issue May 12, 2022
…ty entities.

This should have gone into a separate field in parallel to properties,
not into the properties itself.

Fixes #2537 and also adds a test for the specific question asked in the
ticket.
michael-simons added a commit that referenced this issue May 12, 2022
…ty entities.

This should have gone into a separate field in parallel to properties,
not into the properties itself.

Fixes #2537 and also adds a test for the specific question asked in the
ticket.
@michael-simons michael-simons added this to the 6.1.12 (2021.0.12) milestone May 12, 2022
michael-simons added a commit that referenced this issue May 12, 2022
…ty entities.

This should have gone into a separate field in parallel to properties,
not into the properties itself.

Fixes #2537 and also adds a test for the specific question asked in the
ticket.
@venkat125
Copy link
Author

venkat125 commented Jun 19, 2022

Thanks that worked @michael-simons.
Just having another related doubt on accessing 1-1 target value using person object.
GH2537-question

so in addition to existing model added MotherTongue relationship which is 1-1 as depicted in above diagram
added:

@Getter @Setter @Relationship("MOTHER_TONGUE_IS")
private MotherTongue motherTongue; //field added in Person class

Relationship Entity

@RelationshipProperties
public class MotherTongue {

	@RelationshipId private Long id;

	@TargetNode private final Language language;

	public MotherTongue(Language language) { this.language = language; }

	public Long getId() { return id; }

	public Language getLanguage() { return language; }
}

in this testcase with following @Query

@Query("""
		MATCH (f:Person {id: $person.__id__})
		MATCH (mt:Language {name: $person.__properties__.MOTHER_TONGUE_IS.__target__.__id__})
		MATCH (f)-[frl:MOTHER_TONGUE_IS]->(mt) WITH f, frl, mt
		UNWIND $person.__properties__.KNOWS As rel WITH f, frl, mt, rel
		 MATCH (t:Language {name: rel.__target__.__id__})
		MERGE (f)- [r:KNOWS {description: rel.__properties__.description}] -> (t)
		RETURN f, frl, mt, collect(r), collect(t)
		""")
Person updateRel(@Param("person") Person person);

throws error as follows: (not sure why it got parsed as List(Map) instead of Map as its 1-1 relationship)
Note: MotherTongue passed "English" is 1-1 mapping in model.

Type mismatch: expected a map but was List{Map{__id__ -> NO_VALUE, __properties__ -> Map{}, __target__ -> Map{__labels__ -> List{String("Language")}, __id__ -> String("English"), __properties__ -> Map{}}}}; Error code 'Neo.ClientError.Statement.TypeError'; nested exception is org.neo4j.driver.exceptions.ClientException: Type mismatch: expected a map but was List{Map{__id__ -> NO_VALUE, __properties__ -> Map{}, __target__ -> Map{__labels__ -> List{String("Language")}, __id__ -> String("English"), __properties__ -> Map{}}}}

Is that something has to be modified in the query on accessing target field? @michael-simons
MATCH (mt:Language {name: $person.__properties__.MOTHER_TONGUE_IS.__target__.__id__})

@michael-simons
Copy link
Collaborator

michael-simons commented Jun 20, 2022

Hi. Thanks for your feedback (again) @venkat125 .
I looked into this and while it seems like some "driver /. client" error, it's actual a Cypher error, which made this kinda hard to debug (it led me to the wrong conclusions).

The error your observing results from the fact that we serialize 1:1 relationships like 1:many (as a list of things). This is not intuitive, but it is the way it is right now and I can't change it in 6.x branch.

Your workaround in the above query is would be

@Query("""
		MATCH (f:Person {id: $person.__id__})
		MATCH (mt:Language {name: $person.__properties__.MOTHER_TONGUE_IS[0].__target__.__id__})
		MATCH (f)-[frl:MOTHER_TONGUE_IS]->(mt) WITH f, frl, mt
		UNWIND $person.__properties__.KNOWS As rel WITH f, frl, mt, rel
		 MATCH (t:Language {name: rel.__target__.__id__})
		MERGE (f)- [r:KNOWS {description: rel.__properties__.description}] -> (t)
		RETURN f, frl, mt, collect(r), collect(t)
		""")

See the difference in that MATCH (mt:Language {name: $person.__properties__.MOTHER_TONGUE_IS[0].__target__.__id__}).

Btw, the hint about all relationships being lists of maps is in the docs:

All relationships are lists of maps. Dynamic relationships will be resolved accordingly. If an entity has a relationship with the same type to different types of others nodes, they will all appear in the same list. If you need such a mapping and also have the need to work with those custom parameters, you have to unroll it accordingly. One way to do this are correlated subqueries (Neo4j 4.1+ required).

But I will clarify that.

michael-simons added a commit that referenced this issue Jun 20, 2022
michael-simons added a commit that referenced this issue Jun 20, 2022
# Conflicts:
#	src/test/java/org/springframework/data/neo4j/integration/issues/IssuesIT.java
#	src/test/java/org/springframework/data/neo4j/integration/issues/gh2323/PersonRepository.java
#	src/test/java/org/springframework/data/neo4j/integration/issues/gh2323/PersonService.java
michael-simons added a commit that referenced this issue Jun 20, 2022
# Conflicts:
#	src/test/java/org/springframework/data/neo4j/integration/issues/IssuesIT.java
#	src/test/java/org/springframework/data/neo4j/integration/issues/gh2323/PersonRepository.java
#	src/test/java/org/springframework/data/neo4j/integration/issues/gh2323/PersonService.java
@michael-simons michael-simons mentioned this issue Jan 4, 2023
4 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug A general bug
Projects
None yet
Development

No branches or pull requests

3 participants