Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple Relationship classes with the same type

Using spring-data-neo4j, I want to create two classes using @RelationshipEntity(type="OWNS") to link a Person class to both a Pet and Car.

@RelationshipEntity(type="OWNS")
public class OwnsCar {  
    @Indexed
    private String name;

    @StartNode
    private Person person;

    @EndNode
    private Car car;
}

@RelationshipEntity(type="OWNS")
public class OwnsPet {
    @Indexed
    private String name;

    @EndNode
    private Person person;

    @StartNode
    private Pet pet;
}

This saves to the Graph Database properly with no problems, as I can query the actual Node and Relationship and see they type, etc.

But when I attempt to use @RelatedTo(type="OWNS", elementClass=Pet.class) I either get a class cast exception, or when using lazy-initialization I get incorrect results.

@NodeEntity
public class Person {   
    @Indexed
    private String name;

    @RelatedTo(type="OWNS", direction=Direction.OUTGOING, elementClass=Pet.class)
    private Set<Pet> pets;

    @RelatedTo(type="OWNS", direction=Direction.OUTGOING, elementClass=Car.class)
    private Set<Car> cars;
} 

The result I get when I attempt to print our my person(my toString() has been omitted, but it simply calls the toString() for each field) is this:

Person [nodeId=1, name=Nick, pets=[Car [nodeId=3, name=Thunderbird]], cars=[Car [nodeId=3, name=Thunderbird]]]

Does anyone know if this can be done, should be done, is just a bug or a feature that is missing?

like image 363
Nicholas Avatar asked May 26 '12 02:05

Nicholas


1 Answers

It seems like the problem is, that the annotation causes springDataNeo4j to priorize the relationship name. I tried the same on another sample I created. If both annotations contain type="OWNS" it mixes both 'objects'. When I omit this information, and only use direction and type, it works for me.

Unfortunately this will lead to a problem if you are using another @RelatedTo annotation with more Pets or Cars related with another annotation. As it would not differ between "OWNS" and any other relation to a Pet-Type, the set returns all related pets (example: peter ->(HATES-Relationsip)->dogs).

If it's a bug or not, I can't tell... But for the database: There are only nodes and relations. Both are not typed, so neo4j does not know anything about your 'Pet'- or 'Car'-Class. Spring data neo4j handles this, either by indexing all nodes per type and setting a type-attribute, or using a specific graph-layout (with subreferences). Even if you would want to fetch all pets of a person with a traversal description, you would have so much more code to write, since the outgoing relations with name 'OWNS' contains two types of objects.

I would recommend using two different names. It's easier to write your custom traversals/queries later on, and its probably even faster as well, because no class-type comparison will be needed. Is there any reason, why you would need these specific names?

PS: It is possible, that not everything is 100% accurate. I don't know springdataneo4j in detail, but that's what I figured out so far.

like image 120
Slomo Avatar answered Sep 23 '22 11:09

Slomo