5.4.4.1. EntityManager

EntityManager - основной интерфейс ORM, служит для управления персистентными сущностями.

Tip

В разделе DataManager vs. EntityManager приведена информация о различиях между EntityManager и DataManager.

Ссылку на EntityManager можно получить через интерфейс Persistence, вызовом метода getEntityManager(). Полученный экземпляр EntityManager привязан к текущей транзакции, то есть все вызовы getEntityManager() в рамках одной транзакции возвращают один и тот же экземпляр EntityManager. После завершения транзакции обращения к данному экземпляру невозможны.

Экземпляр EntityManager содержит в себе персистентный контекст – набор экземпляров сущностей, загруженных из БД или только что созданных. Персистентный контекст является своего рода кэшем данных в рамках транзакции.EntityManager автоматически сбрасывает в БД все изменения, сделанные в его персистентном контексте, в момент коммита транзакции, либо при явном вызове метода flush().

Интерфейс EntityManager, используемый в CUBA-приложениях, в основном повторяет стандартный javax.persistence.EntityManager. Рассмотрим его основные методы:

  • persist() - вводит новый экземпляр сущности в персистентный контекст. При коммите транзакции командой SQL INSERT в БД будет создана соответствующая запись.

  • merge() - переносит состояние отсоединенного экземпляра сущности в персистентный контекст следующим образом: из БД загружается экземпляр с тем же идентификатором, в него переносится состояние переданного Detached экземпляра и возвращается загруженный Managed экземпляр. Далее надо работать именно с возвращенным Managed экземпляром. При коммите транзакции командой SQL UPDATE в БД будет сохранено состояние данного экземпляра.

  • remove() - удалить объект из базы данных, либо, если включен режим мягкого удаления, установить атрибуты deleteTs и deletedBy.

    Если переданный экземпляр находится в Detached состоянии, сначала выполняется merge().

  • find() - загружает экземпляр сущности по идентификатору.

    При формировании запроса к БД учитывается представление, переданное в параметре данного метода. В результате в персистентном контексте окажется граф объектов, для которого загружены все атрибуты представления. Если не передано никакого представления, по умолчанию будет использовано представление _local.

    Tip

    В отличие от DataManager, все локальные атрибуты сущностей загружаются независимо от того, указаны ли они в представлении или нет. В EntityManager представление влияет только на загрузку атрибутов-ссылок.

  • createQuery() - создать объект Query или TypedQuery для выполнения JPQL запроса.

  • createNativeQuery() - создать объект Query для выполнения SQL запроса.

  • addView() - аналогичен методу setView(), но в случае наличия уже установленного в EntityManager представления, не заменяет его, а добавляет атрибуты переданного представления.

  • reload() - перезагрузить экземпляр сущности с указанным представлением.

  • isSoftDeletion() - проверяет, находится ли данный EntityManager в режиме мягкого удаления.

  • setSoftDeletion() - устанавливает режим мягкого удаления для данного экземпляра EntityManager.

  • getConnection() - возвращает java.sql.Connection, через который выполняет запросы данный экземпляр EntityManager, и, соответственно, текущая транзакция. Закрывать такое соединение не нужно, оно будет закрыто при завершении транзакции.

  • getDelegate() - возвращает javax.persistence.EntityManager, предоставляемый реализацией ORM.

Пример использования EntityManager в сервисе:

@Service(SalesService.NAME)
public class SalesServiceBean implements SalesService {

    @Inject
    private Persistence persistence;

    @Override
    public BigDecimal calculateSales(UUID customerId) {
        BigDecimal result;
        // start transaction
        try (Transaction tx = persistence.createTransaction()) {
            // get EntityManager for the current transaction
            EntityManager em = persistence.getEntityManager();
            // create and execute Query
            Query query = em.createQuery(
                    "select sum(o.amount) from sample$Order o where o.customer.id = :customerId");
            query.setParameter("customerId", customerId);
            result = (BigDecimal) query.getFirstResult();
            // commit transaction
            tx.commit();
        }
        return result != null ? result : BigDecimal.ZERO;
    }
}
Частичные сущности

По умолчанию, представления в EntityManager влияют только на загрузку связей, т.е. все локальные атрибуты всегда загружаются.

Вы можете заставить EntityManager загружать частичные сущности, если установите свойство loadPartialEntities представления в true (например, так делает DataManager). Однако, если загружаемая сущность кэшируется, то данный признак игнорируется, и сущность все равно будет загружена со всеми локальными атрибутами.