Tell me, please, how to properly use the delayed load strategy in Hibernate. Suppose there is a class Student :

 @Entity @Table(name = "students") public class Student { @Id @Column(name = "student_id") @GeneratedValue(strategy = GenerationType.IDENTITY) public Long id; public String name; public Student(){} public Student(String name){ this.name = name; } } 

and the Room class, which has a reference to the Student class with a one-to-one relationship and using the delayed load strategy fetch = FetchType.LAZY :

 @Entity @Table(name = "rooms") public class Room { @Id public Long id; @Column(name = "number") public int number; @OneToOne( fetch = FetchType.LAZY, optional = false ) @PrimaryKeyJoinColumn public Student student; public Room(){} public Room(int number, Student student) { this.id = student.id; this.number = number; this.student = student; } } 

To get the Room entity, I use the RoomService function of the RoomService class:

 public class RoomService { public RoomService(){} public Room get(long id) throws DBException { Transaction transaction = DBService.getTransaction(); try { Room room = DaoFactory.getRoomDao().get(id); transaction.commit(); return room; } catch (HibernateException | NoResultException | NullPointerException e) { DBService.transactionRollback(transaction); throw new DBException(e); } } 

To obtain a transaction, use the following function from the DBService class:

 public static Transaction getTransaction(){ Session session = DBService.getSessionFactory().getCurrentSession(); Transaction transaction = session.getTransaction(); if (!transaction.isActive()) { transaction = session.beginTransaction(); } return transaction; } } 

Actually, finally the calling code itself:

 StudentService studentService = new StudentService(); RoomService roomService = new RoomService(); try { Student student = studentService.create(new Student("Вася")); Room room = roomService.create(new Room(5, student)); Room room2 = roomService.get(room.id); } 

Actually, the problem is in room2 , since the student field, although not null , but all the fields in room2.student.id and room2.student.name are null . When debugging, you can see that when you call the get function, an org.hibernate.LazyInitializationException occurs org.hibernate.LazyInitializationException you try to get room2.student , that is, the data from the database is not loaded immediately. Due to the fact that the transaction is completed, this data can no longer be obtained.

What needs to be done so that the data can be loaded later? It is clear that you can replace fetch = FetchType.LAZY with fetch = FetchType.EAGER , but then the data will always be loaded, which is not always acceptable. How should an application be properly designed so that you can use a deferred loading strategy?

UPD
RoomDao class RoomDao very short:

 public class RoomDao extends AbstractDao<Room> { RoomDao() { super(Room.class); } } 

And this is the get class get function:

 @Override public T get(long id) { return DBService.getSessionFactory() .getCurrentSession() .get(parameterizedClass, id, LockMode.PESSIMISTIC_READ); } 
  • Unfortunately, the logic of your actions is not clear, and most importantly, what DaoFactory.getRoomDao (). Get (id) ;. In HIBERNATE, only one object with a specific Id can be persistent. - Orthodox
  • To initialize LAZY, you must either request the object's data or execute Hibernate.initialize (student) at the right time; This can be done after the transaction commit. If only objects were persistent. You can see whether the object is persistent (that is, whether it is stored in the persistence cache) by using the utility konopkomikl.ru/2017/06/20/… - Orthodox
  • @Orthodox to check the persistence of an object using persistenceUtil.isLoaded(room.student()) . This expression returns false , i.e. the storage context of the student entity of the room entity is closed. Moreover, even if we add the line Hibernate.initialize(room.student()); to the get function of the RoomService class Hibernate.initialize(room.student()); after the line Room room = DaoFactory.getRoomDao().get(id); , then the initialization of the proxy object room.student will not occur. All fields of this object are null . - golubtsoff
  • @Orthodox if we remove the line optional = false in the Room class, everything works in a magical way. And all because the relation (mapping) of the one-to-one connection with the common primary key with the optional = true parameter does not support deferred data loading, i.e. works the same as with fetch = FetchType.EAGER . Why does not work with optional = false is not clear. - golubtsoff
  • @Orthodox is a small (but significant) explanation to my previous comments. After adding Hibernate.initialize(room.student()); all the fields in room.student are null , but if you go to the field room.student.address in main , the address is read normally. In the absence of Hibernate.initialize(room.student()); an org.hibernate.LazyInitializationException exception was org.hibernate.LazyInitializationException . - golubtsoff

0