2

I have 3 classes, there are User, Role and UserRole. I want to fetch the data of UserRole, but always return NULL.

This is User Class.

@NodeEntity
public class User {
    @GraphId
    Long id;

    @NotNull
    private String username;

    @NotNull
    private String password;

    @NotNull
    private String firstName;

    @NotNull
    private String lastName;

    @NotNull
    private String role;

    @NotNull
    private Boolean active;

    @Relationship(type = "HAS_ROLE", direction = Relationship.OUTGOING)
    private Set<UserRole> userRoles;

    public User() {
        super();
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getRole() {
        return role;
    }

    public void setRole(String role) {
        this.role = role;
    }

    public Boolean getActive() {
        return active;
    }

    public void setActive(Boolean active) {
        this.active = active;
    }

    public Iterable<UserRole> getUserRoles() {
        return userRoles;
    }

    public void setUserRoles(Set<UserRole> userRoles) {
        this.userRoles = userRoles;
    }
}

And this is my Role Class

@NodeEntity
public class Role {
    @GraphId
    Long id;

    @NotNull
    String name;

    @Relationship(type = "HAS_ROLE",direction = Relationship.OUTGOING)
    @JsonIgnore
    private Set<UserRole> userRoles;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }


    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Set<UserRole> getUserRoles() {
        return userRoles;
    }

    public void setUserRoles(Set<UserRole> userRoles) {
        this.userRoles = userRoles;
    }

    public Role() {
        super();
    }
}

And this is my UserRole Class

@RelationshipEntity(type = "HAS_ROLE")
public class UserRole {
    @GraphId
    Long id;

    @StartNode
    @Relationship(type="HAS_ROLE", direction=Relationship.INCOMING)
    User user;

    @EndNode
    @Relationship(type="HAS_ROLE", direction=Relationship.INCOMING)
    Role role;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public Role getRole() {
        return role;
    }

    public void setRole(Role role) {
        this.role = role;
    }

    public UserRole(User user, Role role) {
        super();
        this.user = user;
        this.role = role;
    }

    public UserRole() {
        super();
    }
}

I want to show all the User data, but the result always show userRoles NULL. I am using findAll(1) and findAll(2) but nothing different.

Its different from SDN 3, we only add @Fetch to the field. In SDN 4, no @Fetch annotation. How i can fetch all the data?

UPDATE!!

I changed the class like Luanne answer, and modified the User class like this :

@NodeEntity
public class User {
    @GraphId
    Long id;

    @NotNull
    private String username;

    @NotNull
    private String password;

    @NotNull
    private String firstName;

    @NotNull
    private String lastName;

    @NotNull
    private String role;

    @NotNull
    private Boolean active;

    @Relationship(type = "HAS_ROLE")
    private Set<UserRole> userRoles;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getRole() {
        return role;
    }

    public void setRole(String role) {
        this.role = role;
    }

    public Boolean getActive() {
        return active;
    }

    public void setActive(Boolean active) {
        this.active = active;
    }

    @Relationship(type = "HAS_ROLE")
    public Set<UserRole> getUserRoles() {
        return userRoles;
    }

    @Relationship(type = "HAS_ROLE")
    public void setUserRoles(Set<UserRole> userRoles) {
        this.userRoles = userRoles;
    }

    public User(){
        super();
    }
}

After save the data, and show it, the Roles are shown like this :

[{"id":27,"username":"daviduck123","password":"admin","firstName":"David","lastName":"Vincent","role":"admin","active":null,"roles":{"id":"29","name":"ROLE_ADMIN"}}]

But after that I try to show again all the data, and its back to NULL again like this :

[{"id":27,"username":"daviduck123","password":"admin","firstName":"David","lastName":"Vincent","role":"admin","active":null,"roles":null}]

This is my repository https://github.com/daviduck123/neo4j-ogm-infiniteloop

David Vincent
  • 634
  • 1
  • 8
  • 33
  • User should have a reference to UserRole, not Roles directly, that could be the problem – Luanne Jan 07 '16 at 10:30
  • Yes it is. It's only work once I saved the data and after that its back to null. But when I use UserRole class, its infinite Loop. – David Vincent Jan 07 '16 at 10:38
  • Strange, UserRole should work. Could you upgrade your neo4j-ogm dependency to 1.1.4? There may be some other (fixed) bug in play here. If the problem persists, please open an issue here https://github.com/neo4j/neo4j-ogm/issues with your sample code – Luanne Jan 08 '16 at 03:11
  • I already upgrade neo4j-ogm to 1.1.4 but still not work. Okay, i will open the issue there. Hope i will find some solution. Thanks – David Vincent Jan 08 '16 at 03:50

2 Answers2

2

@RelationshipEntity represents a qualified relationship between two nodes, so the use of @Relationship in it is incorrect.

UserRole should look like

@RelationshipEntity(type = "HAS_ROLE")
public class UserRole {
    @GraphId
    Long id;

    @StartNode
    User user;

    @EndNode
    Role role;

The direction of the relationship in the Role class should be INCOMING since you're defining a HAS_ROLE relationship from User to Role:

    @Relationship(type = "HAS_ROLE",direction = Relationship.INCOMING)
    @JsonIgnore
    private Set<UserRole> userRoles;

   @Relationship(type = "HAS_ROLE",direction = Relationship.INCOMING)    
   public Set<UserRole> getUserRoles() {
        return userRoles;
    }

   @Relationship(type = "HAS_ROLE",direction = Relationship.INCOMING)   
   public void setUserRoles(Set<UserRole> userRoles) {
        this.userRoles = userRoles;
    }

making sure that the accessor and mutator methods are annotated as well (mandatory when you have an INCOMING relationship).

Luanne
  • 19,145
  • 1
  • 39
  • 51
  • I have changed the UserRole class like that, and the Role Class too, add annotation in getter and setter but I am still getting NULL userRoles when show all User data. – David Vincent Jan 07 '16 at 04:17
  • Are you sure you have the right data in the graph? i.e. it's saved with expected labels and relationships? – Luanne Jan 07 '16 at 04:27
  • i have some data, 3 of them have relationship, and the other not. I look at Neo4j graph, and it is showing node "HAS_ROLE". The picture of the graph can be see at http://i67.tinypic.com/nmiv5k.png – David Vincent Jan 07 '16 at 04:41
0

I guess Luanne's solution will work and we should use it. But I have another work around. You can use @Query in repository to customize query. In the query, you can return all object you need and story them into a map.

@Query("match (ac: Address) <-[:at]- (c: Company) <-[:of]- (p: Position) -[:at]-> (a: Address) "
        + "where p.name =~ {0} return p as position, c as company, a as address, ac as companyAddress skip {1} limit {2}")
List<Map<String, Object>> fetchByTitle(String title, int start, int pageSize);

And then later, you need to set relationship manually.

List<Position> positions = new ArrayList<Position>();
    for (Map<String, Object> d : data) {
        Position pos = (Position) d.get("position");
        pos.setCompany((Company) d.get("company"));
        pos.setLocation((Address) d.get("address"));
        pos.getCompany().setAddress((Address) d.get("companyAddress"));
        positions.add(pos);
    }

    return positions;

The pro is you don't need to use @RelationshipEntity, which, as a SQL guy, I am still not comfortable with. The con is that this is not a nature solution.

Junbang Huang
  • 1,927
  • 19
  • 26