Reputation: 6280
I notice when inheritence is used in a spring-data-neo4j 4 data model, the super class is used as the discriminator when loading and discriminating relationships based on end node type. Is there any way I can force spring-data-neo4j-4 to use a subclass as the discriminator instead?
For example, let's say we have a data model (class diagram) as the following on the left and its neo4j database representation on the right.
Currently, if we have an Owner entity with code along the lines of:
@NodeEntity
class Owner extends BaseNodeEntity {
...
@Relationship(type="OWNS")
private Set<Dog> dogs; // both dog and cat are mapped here
@Relationship(type="OWNS")
private Set<Cat> cats; // both dog and cat are mapped here
...
}
The spring-data-neo4j-4 framework will automatically map both Dog and Cat to the set of Cats, and the set of Dogs, so I then have two 'dogs' (although one of them is actually a cat), and two 'cats', (although one of them is actually a dog) loaded from the database. If I remove the super classes Pet and BaseNodeEntity from the data model, then Dog and Cat are automatically mapped to their respective sets correctly.
Is there a way that I can force spring-data-neo4j-4 to map my data model correctly, or will I be forced to change my data model? I'm not keen to remove super classes from my data model as I have a lot of re-use going on, and adding extra relationships (i.e. splitting OWNS to CAT_OWNER and DOG_OWNER) would be similarly annoying.
Update
I've now noticed this behaviour is not consistent. I've written a unit tests that tests the mappings. Strangely, sometimes it passes and sometimes it fails (sometimes it erroneously maps the cat as a dog and the dog as a cat and sometimes it doesn't). Manually running the unit test 10 times gave me the following pass / fail results.
Run, Result (pass / fail)
1 P
2 F
3 F
4 P
5 F
6 P
7 F
8 F
9 P
10 F
Surely mapping behaviour should be consistent. Could this be a bug in SDN-4?
Update 08 May 2016
Sorry about the delay in updating this. I've only just had the opportunity to start working on this project again. I have retested this and am getting the same results with the latest stable neo4j release.
<neo4j.version>2.3.2</neo4j.version>
<sdn.version>4.1.1.RELEASE</sdn.version>
<java.version>1.8</java.version>
<neo4j-ogm.version>2.0.1</neo4j-ogm.version>
<spring-data-commons.version>1.12.1.RELEASE</spring-data-commons.version>
I've attached below the actual domain model used in our test case. The test case details can be seen at https://github.com/johndeverall/thescene-spa/issues/142. The test case code is:
@Test
public void saveAndLoadTags() {
log.info("Given we have a member with some events");
Member member = createMember();
Event event1 = eventService.createEvent("Event1", member);
Event event2 = eventService.createEvent("Event2", member);
log.info("When I tag my events with some tags");
contentService.tag("Tag1", "", event1, member);
contentService.tag("Tag1", "", event1, member); // should create no new tags or relationships
contentService.tag("Tag2", "", event1, member);
contentService.tag("Tag2", "", event2, member);
log.info("Then my events should be appropriately tagged");
event1 = eventService.loadEventBySceneId(event1.getSceneId());
assertThat(event1.getTags().size(), is(equalTo(2)));
assertThat(event2.getTags().size(), is(equalTo(1)));
log.info("And I should have created two tags total");
Iterator<Tag> iterator = contentService.getAllTags().iterator();
List<Tag> tags = StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED), false).collect(Collectors.<Tag> toList());
assertThat(tags.size(), is(equalTo(2)));
log.info("And our member should have created two tags");
member = memberService.loadMemberByEmailAddressPasswordAccount(emailAddress);
// **************************************************************
// member.getCreatedTags().size() more often than not returns 3 causing my test failure!
// **************************************************************
assertThat(member.getCreatedTags().size(), is(equalTo(2)));
}
The problem shown by the test case
The following method:
public Member loadMemberByEmailAddressPasswordAccount(String emailAddress) {
Filter filter = new Filter("email", emailAddress);
Collection<EmailAddressPasswordAccount> emailAddressPasswordAccounts = session.loadAll(EmailAddressPasswordAccount.class, filter, 2);
return emailAddressPasswordAccounts.isEmpty() ? null : emailAddressPasswordAccounts.iterator().next().getMember();
}
Returns a Member object that has a Set of createdTags containing 2 Tags and a tag that is actually an Event.
My actual domain model is below (not simplified to Dogs and Cats):
Additional info:
I have tried annotating all model objects apart from BaseNodeEntity with @NodeEntity annotation. Properties are annotated.
Update 09 May 2016
I get the same intermittent results if I swap out the ogm code for loadMemberByEmailAddressPasswordAccount with derived finder on a repository.
Upvotes: 2
Views: 219
Reputation: 19373
The case above which involved collections of relationships with the same type but different end node types was a bug- http://github.com/neo4j/neo4j-ogm/issues/161
This has been fixed and is available in Neo4j OGM 2.0.2
Upvotes: 1