Второй метод — getReference() (листинг 6.9). Он очень схож с операцией find, поскольку имеет те же параметры, однако извлекает ссылку на сущность (с помощью ее первичного ключа), но не извлекает ее данных. Считайте его прокси для сущности, но не самой сущностью. Он предназначен для ситуаций, в которых требуется экземпляр сущности, находящейся под управлением, но не требуется никаких данных, кроме тех, что потенциально относятся к первичному ключу сущности, к которой осуществляется доступ. При использовании getReference() выборка данных о состоянии является отложенной, а это означает, что, если вы не осуществите доступ к состоянию до того, как сущность окажется отсоединенной, данных уже может не быть там. Если сущность не удастся найти, то будет сгенерировано исключение EntityNotFoundException.
try {
··Customer customer = em.getReference(Customer.class, 1234L)
··// Обработать объект
} catch(EntityNotFoundException ex) {
··// Сущность не найдена
}
Сущность можно удалить методом EntityManager.remove(). Как только сущность окажется удалена, она будет убрана из базы данных, отсоединена от менеджера сущностей и ее больше нельзя будет синхронизировать с базой данных. В плане Java-объектов эта сущность будет по-прежнему доступна, пока не окажется вне области видимости и сборщик мусора не уберет ее. В коде, приведенном в листинге 6.10, показано, как удалить объект после того, как он был создан.
Customer customer = new Customer("Энтони", "Балла", "[email protected]");
Address address = new Address("Ризердаун Роуд", "Лондон", "8QE", "Англия");
customer.setAddress(address);
tx.begin();
em.persist(customer);
em.persist(address);
tx.commit();
tx.begin();
em.remove(customer);
tx.commit();
// Данные удаляются из базы данных, но объект по-прежнему доступен
assertNotNull(customer);
Код из листинга 6.10 создает экземпляр Customer и Address, связывает их (customer.setAddress(address)) и обеспечивает их постоянство. В базе данных строка, касающаяся клиента, связывается со строкой, которая касается адреса, с помощью внешнего ключа; далее в коде удаляется только Customer. В зависимости от того, как сконфигурировано каскадирование (о нем мы поговорим позднее в этой главе), Address может остаться без какой-либо другой сущности, которая ссылается на нее, а строка, касающаяся адреса, станет изолированной.
Изолированные сущности нежелательны, поскольку они приводят к тому, что в базе данных есть строки, на которые не ссылается какая-либо другая таблица, при этом они лишены средств доступа. При использовании JPA вы можете проинформировать поставщика постоянства о необходимости автоматически удалять такие сущности или каскадировать операцию удаления. Если целевая сущность (Address) находится в частном владении источника (Customer), подразумевая, что целью никогда не может владеть несколько источников, а этот источник окажется удален приложением, то поставщик должен будет удалить и цель.
Ассоциации, которые определены как «один к одному» или «один ко многим», поддерживают использование параметра orphanRemoval. Чтобы включить этот параметр в пример, взглянем на то, как добавить элемент orphanRemoval=true в аннотацию @OneToOne (листинг 6.11).
@Entity
public class Customer {
··@Id @GeneratedValue
··private Long id;
··private String firstName;
··private String lastName;
··private String email;
··@OneToOne (fetch = FetchType.LAZY, orphanRemoval=true)
··private Address address;
··// Конструкторы, геттеры, сеттеры
}
При таком отображении код, приведенный в листинге 6.10, автоматически удалит сущность Address, если окажется удалена сущность Customer либо если связь будет разорвана (при присвоении атрибуту address значения null или удалении дочерней сущности из коллекции при связи «один ко многим»). Операция удаления выполняется во время операции сброса (когда имеет место фиксация транзакции).