1

I'm developing a web application with Spring Boot and JPA. I have a class User which, like in a social network, can have followers and followings. I thought that the best way to implement it was by creating a class (FollowRelationship) in which there were two users one followed and the other one following. So in every User class there should be two List of FollowRelatioship objects with different mapping, one for the followers and the other one for the followings. But I think the case is clearer by looking at the code.

@Entity
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer userId;

    @OneToMany(mappedBy="to", cascade = CascadeType.ALL, orphanRemoval=true)
    private List<FollowRelationship> followers = new ArrayList<>();

    @OneToMany(mappedBy="from", cascade = CascadeType.ALL, orphanRemoval=true)
    private List<FollowRelationship> followings = new ArrayList<>();
...
}

And the FollowRelationship class:

@Entity
public class FollowRelationship {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long followRelationshipId;
    private Date date;

    @ManyToOne
    @JoinColumn(name = "from_id")
    @JsonIgnore
    private User from;

    @ManyToOne
    @JoinColumn(name = "to_id")
    @JsonIgnore
    private User to;

    public FollowRelationship(Date date, User from, User to) {
       this.date = date;
       this.from = from;
       this.to = to;
    }

...

}

The method used for creating a FollowRelationship is the following:

@Override
public void follow(Long followerId, Long followedId) throws UserNotFoundException {
    User follower = getByUsername(followerId);
    User followed = getByUsername(followedId);
    follower.addFollowing(new FollowRelationship(new Date(), follower, followed));
    this.userRepository.save(follower);
}

Let's suppose we have two users inside the database, user1 and user2. If I follow user2 with user1 the system correctly creates a FollowRelationship tuple inside the database.

date:2020-02-28 14:38:39    from: user1 to: user2

Sometimes thought it happens that, when the system load the user from the database, it duplicate some following or some follower but I cannot understand why! The question then is: is there something wrong with the solution I have implemented? is there some particular case in which this can produce problems?

I saw the question (Duplicates in OneToMany annotated List) which it seems to talk about the same problem, but I'm not sure because I have a different implementation, it has just one List, I have two on the same Class (FollowRelationship). And even more I'm not that sure about why it is behaving like that,

Stefano Sambruna
  • 767
  • 2
  • 10
  • 29
  • Hard to say without the data in the database tables for problem cases. I can only imagine that sometimes erroneously duplicate data is stored. Your code does little to nothing to prevent that, especially since your'e using a List for the OneToMany relationships rather than a Set. – Gimby Feb 28 '20 at 15:02
  • Inside the database there are no duplicates. Anyway, you are telling me that the recommended data type to use for OneToMany rel is Set? – Stefano Sambruna Feb 28 '20 at 15:04
  • I'm looking into a similar problem ... I'm currently thinking I may need to look at my equals and hashcode implementations ... there are specific things that need to be considered ... the equals method should only use immutable entity attributes ... and the hashcode must be consistent across all entity state transitions ... not sure if that would cause your problem but is good to keep in mind ... Vlad has some good articles on the topic. – James Gawron Feb 28 '20 at 15:09

0 Answers0