-
Dec 13th, 2011, 12:21 PM
#1
Inheritance in spring-data-neo4j
Hi,
I'm using spring-data-neo4j in an object model with inheritance, with a base class Video, a subclass YoutubeVideo and a VideoRepository. The Video base class contains a field "id", which uses @Indexed
When I save a Video instance with an id field a call to VideoRepository.findById returns the object.
However, if I save a YoutubeVideo, the same call to VideoRepository.findById returns null.
Why do I get a different behavior here?
Here are the model classes:
@NodeEntity
public class Video {
@GraphId
public Long nodeId;
@Indexed
public String id;
@Indexed
public String title;
public String description;
public String originalTitle;
public String thumbnailUrl;
}
public class YoutubeVideo extends Video {
public String youtubeId;
}
public interface VideoRepository extends GraphRepository<Video>, NamedIndexRepository<Video>,
RelationshipOperationsRepository<Video> {
Video findById(String id);
}
Here is the test code I use. The second test fails.
@Test
public void findVideo() {
Video video = new Video();
video.setId("test.new");
videoRepository.save(video);
Video existing = videoRepository.findById(video.getId());
assertNotNull(existing);
videoRepository.delete(existing);
existing = videoRepository.findById(video.getId());
assertNull(existing);
}
@Test
public void findVideoSubclass() {
YoutubeVideo video = new YoutubeVideo();
video.setId("test.subclass");
videoRepository.save(video);
Video existing = videoRepository.findById(video.getId());
assertNotNull(existing); <--------- fails
videoRepository.delete(existing);
existing = videoRepository.findById(video.getId());
assertNull(existing);
}
-
Dec 14th, 2011, 03:05 AM
#2
If you use videoRepository.findById() it only looks on the video-repository level (as it only knows about that). It creates a cypher query that uses:
start n = node:Video(id={0}) return n;
There is the @Indexed(level=IndexType.INSTANCE) attribute that makes the field being indexed at the instance-class level and not at the level of the declaring class of the field. I'm just thinking about adding another option that says IndexType.HIERARCHY that adds an index-entry on all levels.
Could you please raise a JIRA issue for this.
Thanks a lot
Michael
-
Dec 14th, 2011, 03:17 AM
#3
Hi Michael,
Thanks for your reply! While I guess I understand why it does happen here (it doesnt find the start node on the index for videos), I am not sure this should be a configurable behavior. For everybody coming from JPA and other object mapping solutions, this would be the expected behavior. Additionally, I saved the Video subclass through the VideoRepository - it's not like I am saving the Object through a YoutubeVideoRepository and retrieve it through a VideoRepository.
BTW, while trying to figure out how spring-data-neo4j handles inheritance, I searched for a test that works with subclasses and repositories. While the test models in org.springframework.data.neo4j.model contain a model with a Car (abstract) base class and two subclasses Toyota and Volvo, they don't seem to be used in any test. Are there any tests that test inheritance with spring-data-neo4j?
Finally, as I am new to cipher, is there any query that I could use to develop my application in the meantime that would give me the desired behavior as a workaround?
Best,
Nils
-
Dec 14th, 2011, 03:24 AM
#4
-
Dec 14th, 2011, 03:27 AM
#5
Nils,
Actually when thinking about it, it should find the start-node as the id field is on the Video class and you didn't specify anything else - that's why the JIRA issue would be helpful to track this.
You can use cypher queries as annotations on repository methods:
@Query("start n=node:Video(id={0}) return n")
Video findById(String id);
you can also query cypher directly via the template.query() methods
there are also more generic index-lookup methods in the repository and template.
out of my head:
repo.findByPropertyValue("id",id);
repo.findAllByPropertyValue("id",id);
template.lookup(Video.class, "id", id).to(Video.class).singleOrNull();
the car inheritance tree is currently used in the advanced-AJ-Mapping tests.
You're right that has to be added to the simple mapping too, fell through the gap 
Could you add this to (another) JIRA issue?
Thanks a lot for your help
Michael
-
Dec 14th, 2011, 03:50 AM
#6
Hi Michael,
I added another issue https://jira.springsource.org/browse/DATAGRAPH-146.
With your approval, I'd even like to raise https://jira.springsource.org/browse/DATAGRAPH-145 to priority critical. WDYT?
Best,
Nils
-
Dec 14th, 2011, 03:55 AM
#7
Thanks Nils,
please leave the prioritizing to me 
we have the GA release next week and I'm not sure it will make it in there. There are still a number of issues to be addressed and lots of docs to update
Cheers
Michael
-
Dec 14th, 2011, 04:38 AM
#8
I understand, this is why I asked first ;-)
BTW, I just added a diff to the issue with a test case. The derived query works when an index name is used on the index property, but fails if the property is indexed without an index name.
So a workaround is to set the index name.
-
Dec 14th, 2011, 09:07 AM
#9
Hi Michael,
I am now running against another problem. While findById now finds the objects, it always returns objects of the base class type. Surprisingly, when I check the return type on the spring-data-neo4j tests I added (see diff uploaded at https://jira.springsource.org/browse/DATAGRAPH-145) everything seems to work. In my local code however, even after adding the constructors that take a Node as parameter, the method still returns the base class.
Any pointers on that one?
Best,
Nils
-
Jun 26th, 2012, 03:36 PM
#10
Any new development on this track? I'm running into very similar problems when doing some inheritance with neo4j and Spring Data.
Thanks.
Eugen.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules