tx.begin();
em.persist(customer);
tx.commit();
assertTrue(em.contains(customer));
tx.begin();
em.remove(customer);
tx.commit();
assertFalse(em.contains(customer));
Очистка и отсоединение. Метод clear() прост: он очищает контекст постоянства, приводя к тому, что все сущности, которые находятся под управлением, оказываются отсоединенными. Метод detach(Object entity) убирает определенную сущность из контекста постоянства. После такого «выселения», изменения, внесенные в эту сущность, не будут синхронизированы с базой данных. Код, приведенный в листинге 6.14, создает сущность, проверяет, находится ли она под управлением, отсоединяет ее от контекста постоянства, а также проверяет, была ли она отсоединена.
Customer customer = new Customer("Энтони", "Балла", "[email protected]");
tx.begin();
em.persist(customer);
tx.commit();
assertTrue(em.contains(customer));
em.detach(customer);
assertFalse(em.contains(customer));
Отсоединенная сущность больше не ассоциирована с контекстом постоянства. Если вы хотите управлять ею, то вам потребуется снова присоединить эту сущность (то есть обеспечить ее слияние). Обратимся к примеру сущности, которую необходимо вывести на JSF-странице. Сущность, сначала загружаемая из базы данных на постоянный уровень (находящаяся под управлением), возвращается из вызова локального EJB-компонента (она является отсоединенной, поскольку контекст транзакции перестает существовать), выводится на уровне представления (все еще являясь отсоединенной), а затем возвращается для обновления в базу данных. Однако в тот момент сущность является отсоединенной, и необходимо присоединить ее снова или обеспечить слияние, чтобы синхронизировать ее состояние с базой данных.
Эта ситуация симулируется в листинге 6.15 путем очистки контекста постоянства (em.clear()), что приводит к отсоединению сущности.
Customer customer = new Customer("Энтони", "Балла", "[email protected]");
tx.begin();
em.persist(customer);
tx.commit();
em.clear();
// Задает новое значение для отсоединенной сущности
customer.setFirstName("Уильям");
tx.begin();
em.merge(customer);
tx.commit();
Код, приведенный в листинге 6.15, создает и обеспечивает постоянство Customer. Вызов em.clear() форсирует отсоединение сущности Customer, однако отсоединенные сущности продолжают присутствовать, но уже вне контекста постоянства, в котором они находились, а синхронизация их состояния с состоянием базы данных больше не обеспечивается. Именно это происходит при использовании customer.setFirstName("William"). Код выполняется в отношении отсоединенной сущности, и данные не обновляются в базе данных. Для репликации этого изменения в базу данных вам потребуется снова присоединить сущность (то есть обеспечить ее слияние) с помощью em.merge(customer) в рамках транзакции.
Обновление сущности является простой операцией, но в то же время может оказаться сложной для понимания. Как вы только что видели, EntityManager.merge() можно использовать для присоединения сущности и синхронизации ее состояния с базой данных. Однако если сущность находится в данный момент под управлением, внесенные в нее изменения не будут автоматически отражены в базе данных. В противном случае вам потребуется явным образом вызвать merge().
В листинге 6.16 демонстрируется обеспечение постоянства Customer с setFirstName, для которого задано значение Antony. Когда вы вызываете метод em.persist(), сущность находится под управлением, поэтому любые изменения, внесенные в эту сущность, будут синхронизированы с базой данных. Когда вы вызываете метод setFirstName(), состояние сущности изменяется. Менеджер сущностей кэширует все действия, начиная с tx.begin(), и обеспечивает соответствующую синхронизацию при фиксации.
Customer customer = new Customer("Энтони", "Балла", "[email protected]");
tx.begin();
em.persist(customer);
customer.setFirstName("Уильям");
tx.commit();