Stephen D
Stephen D

Reputation: 3076

How to make a java class related to another class with Neo4j?

I have a class House and a class Room. Each of these classes are a NodeEntity and are persisted in separate repositories, HouseRepository and RoomRepository. House contains a Set<Room>. I want to be able to delete a Room instance and automatically have that instance removed from the Set<Room> inside of the House class. Since Neo4j is a graph database, I figured that I should be able to declare a relationship between the House and each Room and deleting a Room instance will take care of this automatically. The two following classes represent House and Room.

@NodeEntity
public class House {

    @GraphId
    private Long id;

    @Indexed(unique=true) String uid;

    @RelatedTo (type="addition", direction=Direction.OUTGOING)
    @Fetch
    private Set<Room> rooms;

    public House(String uid, Set<Room> rooms) {
        this.uid = uid;
        this.rooms = rooms;
    }

    public House() {
        this.uid = //random uid;
    }
}


@NodeEntity
public class Room {

    @GraphId
    private Long id;

    @Indexed(unique=true) String uid;

    public Room(String uid) {
        this.uid = uid;
    }

    public Room() {
        this.uid = //random uid;
    }
}

I am thinking that I should be able to write a Cypher query in the RoomRepository that would take care of this, but I am not sure. I have thought of something like this:

public interface RoomRepository extends BaseRepository<Room>{

    @Query("start room=node({0}) " +
            "match house-[:addition*]->room" +
            "delete room")
        public void deleteRoomAndRemoveRoomFromHouse(String uid);
}

What is the recommended way to handle these types of deletes?

Upvotes: 0

Views: 124

Answers (1)

jjaderberg
jjaderberg

Reputation: 9952

Your approach should almost work. You may bump up against an exception because you try to delete a node without first having deleted its relationship. (Unless SDN magic takes care of that for you, but I don't think it intercepts cypher queries.)

As your MATCH clause stands, it will act as a filter, meaning that whatever is bound to the room identifier in your start clause is only retained by the time you reach the delete clause if it has the relevant relationship of at least depth 1. If the room you pass as a parameter does not have at least one incoming [:addition] relationship, it is no longer bound and won't be deleted. Perhaps this is intentional, if so keep it, but add (otherwise replace it with) a match clause that binds all the rooms relationships and deletes them before you delete the room. Try something like

START room=node({0})
MATCH room-[r]-()
DELETE r, room

But I think either the repository or Neo4jTemplate should have plenty of voodoo to take care of this kind of operation for you. Or if you use the advanced mapping with AspectJ, you may have all kinds of chocolate chips baked into your room entity. I know there is a NodeEntity#persist(), I think there is a NodeEntity#remove() as well.

Once the node is deleted, it won't show up in the Set<Room> field of your room class. (If you use simple mapping you may have to retrieve it or sync it manually to the database, possibly a Neo4jTemplate#fetch(), passing the Set<Room> field, will do that for you.)

Upvotes: 1

Related Questions