4.2.6.10. DataManager

Интерфейс DataManager является универсальным средством для загрузки графов сущностей из базы данных, и для сохранения изменений, произведенных в detached экземплярах сущностей.

DataManager всегда стартует новую транзакцию и по завершении работы выполняет коммит, таким образом возвращая сущности в detached состоянии.

DataManager всегда проверяет ограничения подсистемы безопасности на операции и атрибуты сущностей, когда вызывается с клиентской стороны, и игнорирует их по умолчанию когда вызывается из кода Middleware. Если вы хотите, чтобы DataManager проверял эти права доступа и при вызове на среднем слое, получите методом DataManager.secure() специальный объект-обертку и вызывайте методы у него. В качестве альтернативы, вы можете установить свойство приложения cuba.dataManagerChecksSecurityOnMiddleware, чтобы проверка прав работала для всего приложения. Заметьте, что ограничения групп доступа (row-level security) применяются всегда, независимо от того, был ли вызов с клиентского или со среднего слоя.

Методы DataManager:

  • load(), loadList() - загружает граф сущностей в соответствии с параметрами переданного объекта LoadContext.

    В LoadContext обязательно должен быть передан либо JPQL-запрос, либо идентификатор сущности. Если передано и то и другое, используется запрос, а идентификатор игнорируется.

    Правила создания запросов аналогичны описанным в Выполнение JPQL-запросов. Отличием является то, что в запросе LoadContext могут быть использованы только именованные параметры, позиционные не поддерживаются.

    Методы load() и loadList() проверяют наличие у пользователя права EntityOp.READ на загружаемую сущность. Кроме того, при извлечении сущностей из БД накладываются ограничения групп доступа.

    Примеры загрузки сущностей в контроллере экрана:

    @Inject
    private DataManager dataManager;
    
    private Book loadBookById(UUID bookId) {
        LoadContext loadContext = LoadContext.create(Book.class)
                .setId(bookId).setView("book.edit");
        return dataManager.load(loadContext);
    }
    
    private List<BookPublication> loadBookPublications(UUID bookId) {
        LoadContext loadContext = LoadContext.create(BookPublication.class)
                .setQuery(LoadContext.createQuery("select p from library$BookPublication p where p.book.id = :bookId")
                    .setParameter("bookId", bookId))
                .setView("bookPublication.full");
        return dataManager.loadList(loadContext);
    }
  • loadValues() - загружает список пар ключ-значение. Метод принимает ValueLoadContext, в котором задается запрос и список ключей. Возвращаемый список содержит экземпляры KeyValueEntity. Например:

    ValueLoadContext context = ValueLoadContext.create()
            .setQuery(ValueLoadContext.createQuery(
                        "select o.customer, sum(o.amount) from demo$Order o " +
                        "where o.date >= :date group by o.customer")
                .setParameter("date", orderDate))
            .addProperty("customer")
            .addProperty("sum");
    List<KeyValueEntity> list = dataManager.loadValues(context);
  • getCount() - возвращает количество записей для запроса, переданного в метод. Когда возможно, для максимальной производительности, стандартная реализация в классе RdbmsStore выполняет запрос select count() с условиями исходного запроса.

  • commit() - сохраняет в базе данных набор сущностей, переданный в объекте CommitContext. Отдельно указываются коллекции сущностей, которые нужно сохранить, и которые нужно удалить.

    Метод возвращает набор экземпляров сущностей, возвращенных из метода EntityManager.merge(), то есть по сути свежие экземпляры, только что обновленные в БД. Дальнейшая работа должна производиться именно с этими возвращенными экземплярами, чтобы предотвратить потерю данных или исключения оптимистичной блокировки. Для того, чтобы обеспечить наличие нужных атрибутов у возвращенных сущностей, с помощью мэп CommitContext.getViews() можно указать представление для каждого сохраняемого экземпляра.

    Метод commit() проверяет наличие у пользователя права EntityOp.UPDATE на изменяемые сущности, и EntityOp.DELETE на удаляемые.

    Примеры сохранения коллекций сущностей:

    @Inject
    private DataManager dataManager;
    
    private void saveBookInstances(List<BookInstance> toSave, List<BookInstance> toDelete) {
        CommitContext commitContext = new CommitContext(toSave, toDelete);
        dataManager.commit(commitContext);
    }
    
    private Set<Entity> saveAndReturnBookInstances(List<BookInstance> toSave, View view) {
        CommitContext commitContext = new CommitContext();
        for (BookInstance bookInstance : toSave) {
            commitContext.addInstanceToCommit(bookInstance, view);
        }
        return dataManager.commit(commitContext);
    }
  • reload() - удобный метод для перезагрузки экземпляра сущности с требуемым представлением. Делегирует выполнение методу load().

  • remove() - удаляет экземпляр сущности из базы данных. Делегирует выполнение методу commit().

В процессе загрузки данных DataManager может реализовывать дополнительную функциональность, описанную ниже.

Tip

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