Search code examples
hibernateormhibernate-onetomany

Object relational mapping


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


Solution

  • 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.