I deleted merge user method and adding room to room list from the user.
public void save(Room room, User user) {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
try {
session.beginTransaction();
room.getUsers().add(user);
session.merge(room);
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
} finally {
session.close();
}
}
And updating the user instance out the RoomRepository to get the updated User instance:
public void updateUser() {
this.user = userRepository.updateUser(user);
}
On UserRepository:
public User updateUser(User user) {
User result = null;
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
try {
session.beginTransaction();
result = session.get(User.class, user.getId());
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
} finally {
session.close();
}
return result;
}
Probably this is a bad practise, so I'll have to think how to refactor this.
I have class Room and class User with a ManyToMany association.
@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "users")
public Set<Room> rooms = new HashSet<>();
@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinTable(name = "sala_usuario",
joinColumns = @JoinColumn(name = "id_salas"),
inverseJoinColumns = @JoinColumn(name = "cod_user"))
private Set<User> users = new HashSet<>();
This is the exception's trace:
java.lang.IllegalStateException: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: model.Room
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:161)
at org.hibernate.query.spi.AbstractSelectionQuery.list(AbstractSelectionQuery.java:374)
at org.hibernate.query.sqm.internal.QuerySqmImpl.list(QuerySqmImpl.java:1073)
at org.hibernate.query.Query.getResultList(Query.java:94)
at repository.MessageRepository.findRoomMessages(MessageRepository.java:41)
at app.ChatController.loadMessages(ChatController.java:123)
at app.ChatController.lambda$initialize$0(ChatController.java:45)
This is the save method in RoomRepository:
public void save(Room room, User user) {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
try {
session.beginTransaction();
user.getRooms().add(room);
room.getUsers().add(user);
session.merge(room);
session.merge(user);
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
} finally {
session.close();
}
}
The error happens when a Room is opened by the user and try to get the messages with OneToMany association because the instance of Room is not persisted on Hibernate, but it is:
public List<Message> findRoomMessages(Room room) {
List<Message> result = null;
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
try {
session.beginTransaction();
CriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery<Message> query = cb.createQuery(Message.class);
Root<Message> root = query.from(Message.class);
query.select(root).where(cb.equal(root.get("room"), room));
result = session.createQuery(query).getResultList();
session.getTransaction().commit();
} catch (Exception e){
e.printStackTrace();
} finally {
session.close();
}
return result;
}
I've solved making this, but I want to use ORM:
public List<Message> findRoomMessages(Room room) {
List<Message> result = null;
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
try {
session.beginTransaction();
result = session.createNativeQuery("SELECT * FROM mensajes WHERE id_sala = :pid_sala", Message.class)
.setParameter("pid_sala", room.getId()).list();
session.getTransaction().commit();
} catch (Exception e){
e.printStackTrace();
} finally {
session.close();
}
return result;
}
I'm not sure about it and I'm absolutely no hibernate expert but I think you could give it a try.
public void save(Room room, User user) {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
try {
Transaction tx = session.beginTransaction();
room.getUsers().add(user); //it shouldn't be needed to add the room to the users rooms
session.merge(room);//the save operation should be cascaded, so the user should be automatically saved as well
tx.commit();
} catch (Exception e) {
e.printStackTrace();
} finally {
session.close();
}
}