Context
- SDN 3.3.0.RELEASE / 3.4.0.M1
- Neo4j 2.1.7 in distant server mode.
Use case
I have an existing Person in database which can have multiple PersonTranslatedContent that can be in several languages. So basicaly, my modelisation is like :
(:Person)-[:TRANSLATION {lang:"fr}]->(:PersonTranslatedContent)
Problem
When I create a PersonTranslatedContent node and a TRANSLATION relation to link with my Person, the 'lang' property is not persisted on the relationship.
The nodes are corecctly created, but when I query the database from the Neo4j browser, my relationship has only one property : _type__ : PersonToPersonTranslatedContent
Analysis
When logging the HTTP request received by Neo4j, the requets performed are in this order :
1. MATCH (n) WHERE id(n) = {id_n} MATCH (m) WHERE id(m) = {id_m} CREATE (n)-[r:`TRANSLATION`]->(m) SET r={props} RETURN id(r) as id, type(r) as type, r as properties, id(startNode(r)) as start, id(endNode(r)) as end
2. START r=rel({id}) SET r.`_ _type_ _` = {value}
3. START r=rel({id}) RETURN id(r) as id, type(r) as type, r as properties, id(startNode(r)) as start, id(endNode(r)) as end
4. **START r=rel({id}) SET r.`lang` = {value}** <-- here the lang property seems to be correctly set !
5. START r=rel({id}) SET r = {props} <- here, props = {"_ _type_ _" : PersonToPersonTranslatedContent"}
All those REST calls are done within a simple call to personToPersonTranslatedContentRepository.save(). I followed the white rabit in debug mode and here is the shortened call stack :
- Neo4jEntityConverterImpl.write() --> entityStateHandler.useOrCreateState() --> RestAPICypherImpl.createRelationship() (correspond to bullet 1)
- Neo4jEntityConverterImpl.write() --> typeMapper.writeType() --> RestAPICypherImpl.setPropertyOnEntity() (correspond to bullet 2)
- Neo4jEntityConverterImpl.write() --> sourceStateTransmitter.copyPropertiesTo() --> persistentEntity.doWithProperties() --> RestAPICypherImpl.setPropertyOnEntity() (correspond to bullet 4)
- Neo4jEntityConverterImpl.write() --> sourceStateTransmitter.copyPropertiesTo() --> ((UpdateableState)target).flush() --> RestAPICypherImpl.setPropertiesOnEntity() (correspond to bullet 5)
So, in my opinion considering what I know and what I saw during debug, the problem seems to be around the "propertyData" attribute of class RestEntity which is used in the ((UpdateableState)target).flush() ! It always hold the value {"_ type _" : PersonToPersonTranslatedContent"} but never contains my "lang" property.
Note : my problem is the same as the one explain here 3.3.0.M1 : Properties on RelationShipEntity not saved when using CypherRestGraphDatabase?. His post has no satisfying answer.
Can you help me (and him I guess) ?
Thx :)
13/07/15 : Updated
I finally manage to resolve my problem by using :
Map<String, Object> properties = new HashMap<>();
properties.put("lang", lang);
properties.put("__type__", "UserToUserTranslatedContent");
neo4jOperations.createRelationshipBetween(neo4jOperations.getNode(user.getId()), neo4jOperations.getNode(translatedContent.getId()), RelationNames.TRANSLATION, properties);
But it is still strange that simple save() operation do not work as expected
For people looking for a fix, I made a report concerning this problem (https://jira.spring.io/browse/DATAGRAPH-699) and a quick way to use SDN like before (< 3.3.x) is doing like this:
remove "spring-data-neo4j" and "spring-data-neo4j-rest" from your build.gradle and add these lines:
Hope this will help in the mean time of having a real fix ;)