Head's Up! These forums are read-only. All users and content have migrated. Please join us at community.neo4j.com.
01-17-2020 07:07 AM
Good evening,
I'm currently working on an API controller used to edit some node entities and its relationships, the node update is working well but when I update the RelationshipEntities
inside the NodeEntity: Set<ContextRelation>
, its returning the NodeEntity, RelationshipEntities and duplicated RelationshipEntities (they got the same ID and have both the updated values).
Technologies used:
Here is the final JSON example:
{
"data": {
"id": 5,
"contexts": [
{
"id": 18,
"min": 1,
"max": 1,
"definition": {
"id": 8,
"contexts": [],
}
},
{
"id": 18,
"min": 1,
"max": 1,
"definition": {
"id": 8,
"contexts": []
}
}
]
}
}
My aim is to change the "min" and "max" values without making Neo4J creating a new RelationshipEntity id.
Here is my ContextRelation.class
:
@RelationshipEntity(type = RelationType.Names.CONTEXT)
public class ContextRelation extends BaseRelation {
@StartNode
private BaseDefinition from;
@EndNode
private BaseDefinition to;
private Long min;
private Long max;
public ContextRelation() {}
public ContextRelation(BaseDefinition from, BaseDefinition to, Long min, Long max) {
this.from = from;
this.to = to;
this.min = min;
this.max = max;
}
@JsonProperty("definition")
public BaseDefinition getTo() {
return this.to;
}
public Long getMin() {
return this.min;
}
public void setMin(Long min) {
this.min = min;
}
public Long getMax() {
return this.max;
}
public void setMax(Long max) {
this.max = max;
}
}
BaseDefinition.class
:
@NodeEntity(label = NodeType.Names.DEFINITION)
public abstract class BaseDefinition extends BaseGraphObject {
@JsonFilter("DEPTH_ENTITY")
@Relationship(value = RelationType.Names.CONTEXT)
protected Set<ContextRelation> contexts;
public BaseDefinition() {
super();
this.contexts = new ConcurrentSet<>();
}
Here is the place where I edit Set<ContextRelation>
in the Controller:
if(json.get("contexts") instanceof List) {
Map<Long, Map<String, Object>> jsonContexts = new HashMap<>();
((List<Map<String, Object>>) json.get("contexts")).stream()
.filter(ContextRelation::validate)
.filter(c -> !jsonContexts.keySet().contains(Long.valueOf(c.get("definition").toString())))
.forEach(c -> jsonContexts.put(Long.valueOf(c.get("definition").toString()), c));
Map<Long, ContextRelation> definitionContexts = definition.getContexts().stream()
.collect(Collectors.toMap(c -> c.getTo().getId(), c -> c));
for(ContextRelation currentContext : definitionContexts.values()) {
if(!jsonContexts.keySet().contains(currentContext.getTo().getId())) {
definition.getContexts().remove(currentContext);
} else {
Map<String, Object> currentJsonContext = jsonContexts.get(currentContext.getTo().getId());
definition.getContexts().remove(currentContext);
currentContext.setMax(currentJsonContext.get("max") == null ? null : Long.valueOf(currentJsonContext.get("max").toString()));
currentContext.setMin(currentJsonContext.get("min") == null ? null : Long.valueOf(currentJsonContext.get("min").toString()));
definition.getContexts().add(currentContext);
definitionContexts.put(currentContext.getTo().getId(), currentContext);
}
}
for(Map<String, Object> currentContext : jsonContexts.values()) {
if(ContextRelation.validate(currentContext) && !definitionContexts.keySet().contains(Long.parseLong(currentContext.get("definition").toString()))) {
BaseDefinition contextDefinition = repository.find(Long.valueOf(currentContext.get("definition").toString()));
if(contextDefinition == null)
errors.put("contexts", "One context definition's id is incorrect");
else
definition.getContexts().add(
new ContextRelation(
definition,
contextDefinition,
currentContext.get("min") == null ? null : Long.parseLong(currentContext.get("min").toString()),
currentContext.get("max") == null ? null : Long.parseLong(currentContext.get("max").toString())
)
);
}
}
}
definition = repository.createOrUpdate(definition);
ApiUtils.respond(context, "Définition modifée avec succès", Response.OK, definition);
Do you guys have any idea about this problem ?
Thank you
01-20-2020 03:12 AM
@gerrit.meier Sorry for the ping, but I'm struggling so hard on this problem and I know you're really confident with Neo4J, do you have an idea on this ?
01-20-2020 05:43 AM
Okay, I think I've found a solution for this: I think that the fact the ContextRelation
is being edited and is part of the BaseDefinition::contexts
Set, the OGM thinks it has to update one relation and to create a new one.
Actually in the DB there's only one but, these two instructions let me think that it is unable to share the relation's ids between the instruction. So I tried to force every instructions of the Edit Controller to use the same Neo4J Session, which worked fine !
Even if that solved the problem, I'm not sure if my understanding of the bug is good or not and, I would be glad to have some feedback on it
01-21-2020 02:34 PM
Welcome to the Neo4j community and sorry for the late reply.
Besides the code your assumption is right: You should always operate within the same session for one unit of work (load, edit, save).
Unfortunately I cannot see where the definition
comes from in your last snippet.
Actually in the DB there's only one but, these two instructions let me think that it is unable to share the relation's ids between the instruction
Do you mean before or after the edit?
02-10-2020 01:26 AM
Sorry for the late reply, the notification email was flagged as spam
I mean after the edit, that's what was strange, it returned me two relations but when doing a MATCH (n) RETURN n;
through the Neo4J Browser, the graph was only containing one relationship
All the sessions of the conference are now available online