cancel
Showing results for 
Search instead for 
Did you mean: 

Head's Up! These forums are read-only. All users and content have migrated. Please join us at community.neo4j.com.

OGM Not deleting relationship on save()

Hi guys,

I'm trying to remove a relationship from an @NodeEntity, when using debugger, the breakpoints indicates that the object isn't containing any relation in outgoingRelations and incomingRelations but when the transaction is comitted, it refills the outgoingRelations with the relation I just removed... I don't understand why, but after a long debug, I found that the OGM never identified that the relations had changed, the only statement being executed in the DB is the one to update the Node body only.

Do you guys have any idea on how to fix that ? here's my code :

//BaseNode.java
public class BaseNode extends BaseGraphObject {
    @Properties
    protected Map<String, Object> attributes;
    @Relationship(type = "RELATION")
    protected List<BaseRelation> outgoingRelations;
    @Relationship(type = "RELATION", direction = Relationship.INCOMING)
    protected List<BaseRelation> incomingRelations;
    protected Long x;
    protected Long y;

    public BaseNode() {
        super();
        this.attributes = new HashMap<>();
        this.outgoingRelations = new ArrayList<>();
        this.incomingRelations = new ArrayList<>();
    }

public List<BaseRelation> getIncomingRelations() {...}
public List<BaseRelation> getOutgoingRelations() {...}
//BaseNodeUtil.java
public static void updateRelations(BaseNode node, Map<Object, Object> json, Session session) throws ApiException {
// [...]
for(int i = 0 ; i < node.getOutgoingRelations().size(); i++) {
        BaseRelation relation = node.getOutgoingRelations().get(i);

        if(!relation.getType().equals(RelationType.GROUP.toString()))
                node.getOutgoingRelations().remove(i);
    }
}
//BaseNodeEditHandler.java
public class BaseNodeEditHandler extends AsyncHandler {
    @Override
    public boolean asyncTask(ApiCompletableFuture api, Context context, Session session) throws Exception {
        BaseDefinition definition = repository.find(Long.parseLong(context.pathParam("id")));

        definition.setIcon(Icon.valueOf(json.get("icon").toString()));
        definition.setX(Long.valueOf(json.get("x").toString()));
        definition.setY(Long.valueOf(json.get("y").toString()));
        BaseNodeUtil.updateRelations(definition, json, session);
        definition.validate();

        definition = repository.createOrUpdate(definition, session);

        return api.success("Definition has been successfully edited", GraphUtil.format(repository.find(definition.getId())));
    }
}

Edit: I also noticed that removing the session param from the createOrUpdate, fixed the problem, but I need it to work in a transaction that I can rollback on Exception

9 REPLIES 9

@gerrit.meier Sorry for the ping, but I think you're the only one who can help me on this 😕

As the relation I tried to remove is a RelationshipEntity, I directly did session.delete(relation) which is working fine, but if you have the time, I would be glad to understand why my first attempt didn't worked

I wonder what your repository look like, or at least what repository.createOrUpdate(definition, session) and repository.find(Long.parseLong(context.pathParam("id"))) do.
I assume that your are not using only using the Spring Data repository but something else because there is no createOrUpdate method in there.

I assume that the loading of the definition in the BaseNodeEditHandler takes place in another session then the createOrUpdate which makes Neo4j-OGM unaware of the already existing relationships and cannot decide if it needs to get deleted or not.

Here is the createOrUpdate method, its inside a GenericCrud<T> (from the GenericService in this example: https://neo4j.com/docs/ogm-manual/current/tutorial/)

public abstract class GenericCrud<T> implements Crud<T> {
    private static final int DEPTH_LIST = 0;
    private static final int DEPTH_ENTITY = -1;
    protected Session session = HedgeSessionFactory.getInstance().getSession();

    public abstract Class<T> getEntityType();

    @Override
    public T find(Long id) {
        Class<T> entityType = getEntityType();
        return this.session.load(entityType, id, entityType.equals(BaseRelation.class) ? 1 : DEPTH_ENTITY);
    }
    @Override
    public T find(Long id, Session session) {
        Class<T> entityType = getEntityType();
        return session.load(entityType, id, entityType.equals(BaseRelation.class) ? 1 : DEPTH_ENTITY);
    }

    @Override
    public T createOrUpdate(T entity) {
        this.session.save(entity, DEPTH_ENTITY);
        return find(((BaseGraphObject) entity).getId());
    }
    @Override
    public T createOrUpdate(T entity, Session session) {
        session.save(entity, DEPTH_ENTITY);
        return find(((BaseGraphObject) entity).getId());
    }
}

I think my assumption is still valid. the createOrUpdate uses the GenericCrud class' session but the find operates with a provided one. If those Sessions are not the same, they won't share a cache and the one that is responsible for the save does not know about the changes that happened in the entity but only "sees" the current state.

@gerrit.meier this is very common problem faced by many people including me but have not found a suitable solution. I have User Nodes in neo4j database. each user has contact relationship with some other users. now I want to delete this contact relationship for a user.
e.g. i have user1 and user2 relating with each other on contact relation.
User {
...properties
@Relationship("CONTACT")
public Set contacts = new HashSet<>():
}
now I am deleting for user1.getContacts().remove(user2); //it remove user2 from list ok
userRepo.save(user1); //but here it doesn't save these changes

Do you mean that you defined this on both sides? If so, you would also have to remove it in both User contact lists.

[How to delete a relationship of a neo4j node in spring data - Stack Overflow](https://how to delete a relationship of a neo4j node in spring data) a question I asked on stackoverflow. If you can answer there Please.
I see this warning from spring boot and doesn't update the node WARN 12167 --- [nio-8080-exec-9] o.s.d.n.c.m.DefaultNeo4jIsNewStrategy : Instances of class com.talkkia.api.entity.User with an assigned id will always be treated as new without version property!

Ah....so this is unrelated to Neo4j-OGM but a SDN problem you are facing. Will answer on SO.