artemisian
artemisian

Reputation: 3106

Spring Neo4j - Bolt driver fails to load a relationship while the Http driver does it successfully

While coding a poc with Spring Neo4j using spring boot I came across what it seems to be an inconsistent behavior between the Bolt driver and the Http driver. Basically after saving a rich relationship between 2 nodes the test fails to load it when using the Bolt driver, however the exact same test succeeds when trying with the Http driver.

The sample project can be downloaded from github

It's a very basic/straight forward test, the only pre-requisite is that you will need to have Neo4j 3 installed with the Bolt connector enabled.

As suggested by Andrej please find below the relevant sections of the code:

@NodeEntity(label = "Person")
public class Person {
    private Long id;
    private String firstname;
    private String lastname;

    @Relationship(type = "HAS_CONTACT", direction = Relationship.INCOMING)
    private Contact contact;

    // getters and setters here ......... 
}

@NodeEntity(label = "BankAccount")
public class BankAccount {

    private Long id;
    private Integer balance;

    @Relationship(type = "HAS_CONTACT")
    private List<Contact> contacts = new ArrayList<>();

    // getters and setters here ......... 
}

@RelationshipEntity(type = "HAS_CONTACT")
public class Contact {

    public Contact() {
    }

    public Contact(BankAccount bankAccount, Person person) {
        this.bankAccount = bankAccount;
        this.person = person;

        this.bankAccount.getContacts().add(this);
        this.person.setContact(this);
    }

    private Long id;

    @StartNode
    private BankAccount bankAccount;

    @EndNode
    private Person person;

    private String email;
    private String phoneNumber;

    // getters and setters here .........
}

@Repository
public interface ContactRepository extends GraphRepository<Contact> {

    @Query("MATCH (a:BankAccount)-[r:HAS_CONTACT]->(:Person) " +
            "WHERE ID(a)={accountId} " +
            "RETURN r")
    Iterable<Contact> findByAccountId(@Param("accountId") Long accountId);
}

After saving 1 account, 1 person and 1 contact relationship between them the below query is the one that fails:

Iterable<Contact> contacts = contactRepository.findByAccountId(accountId);

// this assertion will Fail for the BOLT driver, however, it will Succeed for the HTTP driver
// if the accountRepository.findOne(accountId) statement is executed before calling
// contactRepository.findByAccountId(accountId) then the test will also succeed for the BOLT driver
assertThat(size(contacts), is(1)); 

Upvotes: 1

Views: 154

Answers (1)

artemisian
artemisian

Reputation: 3106

See below the response from the neo4j team about the issue:

The reason the relationship entity cannot be mapped is because the start and end node are unavailable with this query:

 @Query("MATCH (a:BankAccount)-[r:HAS_CONTACT]->(p:Person) " +
            "WHERE ID(a)={accountId} " +
            "RETURN r,")
    Iterable<Contact> findByAccountId(@Param("accountId") Long accountId);

You need to return these nodes to be able to construct a valid relationship entity, like this:

 @Query("MATCH (a:BankAccount)-[r:HAS_CONTACT]->(p:Person) " +
            "WHERE ID(a)={accountId} " +
            "RETURN r,a,p")
    Iterable<Contact> findByAccountId(@Param("accountId") Long accountId);

It's a side effect of the HTTP endpoint that allows this to pass- the start and end node are returned by this endpoint anyway. Please see http://graphaware.com/neo4j/2016/04/06/mapping-query-entities-sdn.html for more info.

Upvotes: 1

Related Questions