Currently, We're working on OGM base implementation. We like to move on SDN 6 But I face problem to update relationship by neo4jRepository. I mention domain model.
@Node
public class Activity {
@Id
@GeneratedValue
protected Long graphId;
private String guid;
@Relationship(type = "PARENT_OF", direction = Direction.OUTGOING)
private Set<Activity> children;
public void addChild(Activity child) {
this.children.add(child);
}
public void removeChild(Activity child) {
this.children.remove(child);
}
}
public interface ActivityReadRepository extends Neo4jRepository<Activity, Long>{
}
@Component
public class RunableClass implements CommandLineRunner{
@Autowired
ActivityRepository activityRepository;
@Override
public void run(String... args) throws Exception {
Activity parent = activityRepository.findByGuid("xxx-xxx-xxx-xxx-xxx")
Activity child = activityRepository.findByGuid("xxx-xxx-xxx-xxx-xxx1")
parent.removeChild(child);
activityRepository.save(parent);
}
}
After used save() Method, All Child `PARENT_OF` relationship will be removed. That above code working fine in SDN+OGM, but it does not work on SDN 6.
Has your ` findByGuid` method a custom query annotation? I ask because it seems that the parent is not fully hydrated. SDN will remove and re-create all relationships to keep the Java model(s) in sync with the database. (https://docs.spring.io/spring-data/neo4j/docs/current/reference/html/#query-creation.save)
If you don't want / can load the full ` Activity`` , it might also be helpful to have a look at the projection support in SDN that will only load and/or persist a part of your domain. https://docs.spring.io/spring-data/neo4j/docs/current/reference/html/#projections
` findByGuid` do not custom query. I try to fetch full `Activity`.
public interface ActivityReadRepository extends Neo4jRepository<Activity, Long>{
Activity findByGuid(String Guid)
}
I used about code for fetch parent and child Activity.
I want to change parent of Child Activity. But it does not work. Do Projection update relationship ? I asked because i used projection, it did the same as by entity.
Yes, it would also work the same way with projection. But I it was more related in cases you do not want to fetch everything (maybe a topic later).
Have you checked the activity parent entity before the save? Does it contain other ` Parent_Of` elements at all?
Although it should not make any differences, you could try to remove the child from the parent's list by iterating through the already loaded children list and removing the child with the given uuid.
- Have you checked the activity parent entity before the save ?
Yes checked its contain child activity
I used projection to save children.
public class ActivityDetails {
private Long graphId;
private Set<Activity> children;
public Long getGraphId() {
return graphId;
}
public void setGraphId(Long graphId) {
this.graphId = graphId;
}
public Set<Activity> getChildren() {
return children;
}
public void setChildren(Set<Activity> children) {
this.children = children;
}
}
@Component
public class RunableClass implements CommandLineRunner{
@Autowired
Neo4jTemplate neo4jTemplate;
@Override
public void run(String... args) throws Exception {
ActivityDetails activityInf =activityReadRepository.findByGraphId(167L); // Without @Query annotation
neo4jTemplate.save(Activity.class).one(activityInf);
}
}
After saved, I got below logs.
2022-07-22 11:42:12,305Z | DEBUG | main | org.springframework.data.neo4j.cypher | correlationId:- | Executing:
OPTIONAL MATCH (hlp:`Activity`:`AbstractGraphNodeEntity`:`IGraphNodeEntity`) WHERE id(hlp) = $__id__ WITH hlp WHERE hlp IS NULL CREATE (activity:`Activity`:`AbstractGraphNodeEntity`:`IGraphNodeEntity`) SET activity = $__properties__ RETURN activity UNION MATCH (activity:`Activity`:`AbstractGraphNodeEntity`:`IGraphNodeEntity`) WHERE id(activity) = $__id__ SET activity += $__properties__ RETURN activity
2022-07-22 11:42:12,323Z | DEBUG | main | org.springframework.data.neo4j.cypher | correlationId:- | Executing:
MATCH (startNode)-[rel:`PARENT_OF`]->(:`Activity`:`AbstractGraphNodeEntity`:`IGraphNodeEntity`) WHERE (id(startNode) = $fromId AND NOT (id(rel) IN $__knownRelationShipIds__)) DELETE rel
I don't know why it deleted Parent_of relationship in save method. If it already contains in projection class.
I need to ask this explicitly before investigating further: As described in the linked documentation, the removal of all PARENT_OF relationships is nothing unusual.
Is this your problem or that there are no relationships is the database anymore.
Sorry to ask but I am not 100% sure what the question is.
Database contain PARENT_OF relationship, If I try to update current relationship by save method, SDN removed all sub graph node relationship as i mansion before.
I only need to update a targeted node of relationship. When tried it by projection as well as with repository, it did not work. It removed current relationship. Yes, it is a problem.
I could not exactly reproduce your problem but I think it is the very same root cause:
When fetching the parent and the child separately, parent's child and loaded child are different objects.
Removing the child would fail if it does not "look like" the one that is in the parent's collection.
To remove the child properly from the list, you have to implement equals/hashCode like
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Activity activity = (Activity) o;
return graphId.equals(activity.graphId) && guid.equals(activity.guid);
}
@Override
public int hashCode() {
return Objects.hash(graphId, guid);
}
I created an example based on the information you provided: https://github.com/meistermeier/neo4j-issues-examples/tree/master/community-58196