Список станів
А тепер починається найцікавіше. Ми вивчатимемо стани Entity-об'єктів. За все потрібно платити і за використання Hibernate теж. Чи не думаєш ти, що вивчення HQL – це і є така плата? Ні, життя влаштоване трохи складніше.
Якщо у тебе є якийсь Entity-об'єкт, який ти можеш зберігати в базу за допомогою Hibernate, то з погляду Hibernate цей об'єкт може мати чотири стани:
- Transient
- Persistent (або Managed)
- Detached
- Removed
А щоб тебе зацікавити, додам до цієї лекції ось таку картинку:

Transient
Насправді все значно простіше, ніж здається, хоча і не без нюансів. Наприклад, кожен Entity об'єкт, який ти створив за допомогою Java-коду, а не завантажив з бази за допомогою Hibernate, має статус Transient (прозорий).
EmployeeEntity employee = new EmployeeEntity();
Статус Transient означає, що Hibernate поняття не має про цей об'єкт, і жодні дії з об'єктом не впливають на Hibernate, як і робота Hibernate на цей об'єкт.
Такі об'єкти ще називають POJO - Plain Old Java Object . Цей термін часто використовується як протилежність до різних об'єктів з хитрою поведінкою. Ось пам'ятаєте Moc-об'єкти, які створював Mockito? Ось вони не POJO.
Якщо якийсь клієнтський код працює з об'єктом зі статусом Transient, їх взаємодію можна описати супер-простий схемою:

Persistent or Managed
Наступний найпоширеніший випадок - це об'єкти, пов'язані з двигуном Hibernate. Їх статус називають Persistent (або Managed). Способів отримати об'єкт із таким статусом рівно два:
- Завантажити об'єкт з Hibernate.
- Зберегти об'єкт у Hibernate.
Приклади:
Employee employee = session.load(Employee.class, 1);
Employee employee = new Employee ();
session.save(employee);
Такому об'єкту зазвичай відповідає якийсь запис у базі даних, він має ID тощо. Цей об'єкт приєднаний до сесії Hibernate'а, і взагалі може бути не реальним об'єктом, а якимось proxy.
Цілком реальна ситуація, коли після виклику методу session.load() тобі повернуть якийсь об'єкт-заглушку (proxy), і всі звернення до бази даних будуть виконуватися тільки після виклику методів цього об'єкта. Але про такі деталі ми поговоримо трохи згодом.
А взаємодію клієнтського коду та об'єкта в статусі Managed можна описати ось такою картинкою:

Detached
Наступний стан – це коли об'єкт було від'єднано від сесії. Тобто колись об'єкт було приєднано до сесії Hibernate, але потім сесія закрилася або транзакція завершилася, і Hibernate більше не стежить за цим об'єктом.
Приклад:
session.close();
session.evict(entity);
У першому прикладі сесію було закрито. У другому випадку ми явно вказали, що хочемо від'єднати об'єкт від сесії за допомогою evict() .
Нова схема взаємодії коду та об'єкта виглядатиме так:

І ось тут буде найцікавіше. Якщо твій об'єкт був отриманий з Hibernate, то велика ймовірність, що тобі віддали якийсь проксі замість реального об'єкта. І цей proxy-об'єкт після від'єднання від сесії кидатиме винятки при виклику його методів.
Це найчастіша проблема у всіх новачків під час роботи з Hibernate. Тобі потрібно точно знати у кожен момент часу відповідь на такі питання, коли ти працюєш з Entity-об'єктом :
- У тебе є реальний об'єкт чи тільки proxy від реального об'єкта?
- Ти зараз у транзакції чи ні?
- Це read-write транзакція чи read-only транзакція?
- Об'єкт керується механізмом LazyLoading?
- Які частини об'єкта вже завантажені на згадку, а які будуть завантажені при зверненні?
- Як твій об'єкт пов'язаний із залежними об'єктами?
Хороша новина – здебільшого все очевидно. Але тобі все одно треба розуміти, як усе це працює під капотом. Декларативне програмування воно таке – написати код можна за 10 хвабон, зрозуміти чому він не працює, як треба – за 10 годин :)
Removed
І останній стан, який може бути у твого Entity-об'єкта – це Removed. Як ти вже напевно здогадався з його назви – стан віддаленого об'єкта.
Такий стан з'являється через те, що якщо ти видалиш якийсь об'єкт з бази, то Java-об'єкт відразу нікуди не зникне.
Employee employee = session.load(Employee.class, 1);
//після завантаження об'єкта стан Persisted
session.remove(employee);
//після видалення об'єкта стан Removed
session.save(employee);
//а тепер знову Persisted
session.close();
//а тепер стан Detached
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ