I am trying to design some kind of user to user relationship, such as "user A follows user B" and "User A wants to be User B's friend".
I have a User class, and the way it is designed looks like this:
@Entity
public class User{
@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
List<User> followers;
@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
List<User> following;
@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
List<User> friendRequests;
@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
List<User> requesting;
@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
List<User> friends;
}
I am running into two problems:
I have a feeling that the relationship is not defined properly, and also I should be seeing more tables, because right now, I only see User table, and User_User table.
The following creates 3 table, friends, followers, and requesters. Is this somewhat optimized compared to 5 tables? And are there any advantage to this in comparison with what Mr.J4mes suggested?
@ManyToMany
@JoinTable(name = "followers", joinColumns = @JoinColumn(name = "followerId"), inverseJoinColumns = @JoinColumn(name = "userId"))
private List<User> followers;
@ManyToMany
@JoinTable(name = "followers", joinColumns = @JoinColumn(name = "userId"), inverseJoinColumns = @JoinColumn(name = "followerId"))
private List<User> following;
@ManyToMany
@JoinTable(name = "friends", joinColumns = @JoinColumn(name = "userId"), inverseJoinColumns = @JoinColumn(name = "friendId"))
private List<User> friends;
@ManyToMany
@JoinTable(name = "requesters", joinColumns = @JoinColumn(name = "requesterId"), inverseJoinColumns = @JoinColumn(name = "userId"))
private List<User> friendRequests;
@ManyToMany
@JoinTable(name = "requesters", joinColumns = @JoinColumn(name = "userId"), inverseJoinColumns = @JoinColumn(name = "requesterId"))
private List<User> requesting;
First of all, to implement your feature, you should use @ManyToMany
instead of @OneToMany
. It should look like this:
@Entity
public class User implements Serializable {
@ManyToMany(mappedBy="followers")
@JoinTable(name="followingTable")
private Set<User> following;
@ManyToMany
@JoinTable(name="followerTable")
private Set<User> followers;
@ManyToMany(mappedBy="friendRequests")
@JoinTable(name="requestingTable")
private Set<User> requesting;
@ManyToMany
@JoinTable(name="friendRequestTable")
private Set<User> friendRequests;
@ManyToMany
private Set<User> friends;
}
Your relationships looks like bidirectional ones to me. If you use @OneToMany
, it means that C has 2 followers A and B
= A and B only follows C
. However, the fact is that one person can follows many people and one person can be followed by many people. In other words, A and B can also follow D
.
Besides, you shouldn't use cascadeType.ALL
at all. That cascade policy means that if one user deletes his account and you delete the corresponding entry in the database, all of his friends, etc. will also be deleted.