I am very new to ORM and can any one suggest an Idea to over come the following scenario.
I have a Chat Class as bellow
@Entity
public class Chat {
@Id
@GeneratedValue
@Column(name="Id")
private int id;
@ManyToOne
private User userSent;
@ManyToOne
private User userRecieve;
private Date time;
@Column(name="message", length=50)
private String message;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Date getTime() {
return time;
}
public void setTime(Date time) {
this.time = time;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
And the User class as bellow
@Entity
public class User {
@Id
@GeneratedValue
private Integer id;
private String name;
private String email;
private String password;
@OneToMany
private List<Chat> chats;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public List<Chat> getChats() {
return chats;
}
public void setChats(List<Chat> chats) {
this.chats = chats;
}
}
And my problem is a User has many chats and the chat has 2 different type of users as reciever and sender but both of them are belongs to one particular chat.
And My question is how can I declare it how to give the relationship. thanks in advance
It is not possible to express a bidirectional two to many relationship (where both of that two are distinct fields) with JPA in a simple manner.
The most simple way to solve this is to make the relation unidirectional by removing the chats
field from User
. Then in your repository/DAO for Chat
you provide a function findByUser
with a query like
SELECT Chat c WHERE c.userSent = :user OR c.userReceive = :user
This way you can still get the collection of chats for a given user, just not through the User
entity itself.
Another solution would be to make the relation many to many and add a property to the relation that indicates the user's type of participation in the chat. You would have to create an intermediate entity like
@Entity
public class ChatParticipation {
public static enum Type {
SENDER,
RECEIVER
}
private Chat chat;
private User user;
private Type type;
}
And modify the other entities' getters
@Entity
public class Chat {
@OneToMany
private Set<ChatParticipation> participations;
public User getSender() {
return participations.stream()
.filter(p -> p.getType() == ChatParticipation.Type.SENDER)
.map(ChatParticipation::getUser)
.findFirst().get();
}
public User getReceiver() {
return participations.stream()
.filter(p -> p.getType() == ChatParticipation.Type.RECEIVER)
.map(ChatParticipation::getUser)
.findFirst().get();
}
}
@Entity
public class User {
@OneToMany
private Set<ChatParticipation> participations;
public Set<Chat> getChats() {
return participations.stream()
.map(ChatParticipation::getChat)
.collect(Collectors.toSet());
}
}
You should probably cache the getter results. Also you have to come up with a solution for the setters.