5.2.6.10. DataManager
Интерфейс DataManager является универсальным средством для загрузки графов сущностей из базы данных, и для сохранения изменений, произведенных в detached экземплярах сущностей.
|
Tip
|
В разделе DataManager vs. EntityManager приведена информация о различиях между DataManager и EntityManager. |
DataManager на самом деле делегирует выполнение реализациям DataStore, и поддерживает ссылки между сущностями из разных хранилищ. Большинство деталей реализации, описанных ниже, актуальны только когда производится работа через RdbmsStore с сущностями, хранящимися в реляционной БД. Для другого типа хранилища все, кроме сигнатур методов, может отличаться. Для простоты изложения, далее, когда мы говорим просто DataManager, мы будем иметь в виду DataManager через RdbmsStore.
Методы DataManager:
-
load(Class)- загружает сущности указанного типа. Данный метод является точкой входа в fluent API:@Inject private DataManager dataManager; private Book loadBookById(UUID bookId) { return dataManager.load(Book.class).id(bookId).view("book.edit").one(); } private List<BookPublication> loadBookPublications(UUID bookId) { return dataManager.load(BookPublication.class) .query("select p from library$BookPublication p where p.book.id = :bookId") .parameter("bookId", bookId) .view("bookPublication.full") .list(); } -
loadValues(String query)- загружает пары ключ-значение по запросу, возвращающему скалярные значения. Данный метод является точкой входа в fluent API:List<KeyValueEntity> list = dataManager.loadValues( "select o.customer, sum(o.amount) from demo$Order o " + "where o.date >= :date group by o.customer") .properties("customer", "sum") .parameter("date", orderDate) .list(); -
loadValue(String query, Class valueType)- загружает единственное значение по запросу. Данный метод является точкой входа в fluent API:BigDecimal sum = dataManager.loadValue( "select sum(o.amount) from demo$Order o " + "where o.date >= :date group by o.customer", BigDecimal.class) .parameter("date", orderDate) .one(); -
load(LoadContext),loadList(LoadContext)- загружает сущности в соответствии с параметрами переданного объектаLoadContext. ВLoadContextобязательно должен быть передан либо JPQL-запрос, либо идентификатор сущности. Если передано и то и другое, используется запрос, а идентификатор игнорируется. Примеры:@Inject private DataManager dataManager; private Book loadBookById(UUID bookId) { LoadContext<Book> loadContext = LoadContext.create(Book.class) .setId(bookId).setView("book.edit"); return dataManager.load(loadContext); } private List<BookPublication> loadBookPublications(UUID bookId) { LoadContext<BookPublication> 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)- загружает список пар ключ-значение. Метод принимает объект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(LoadContext)- возвращает количество записей для запроса, переданного в метод. Когда возможно, для максимальной производительности, стандартная реализация в классеRdbmsStoreвыполняет запросselect count()с условиями исходного запроса. -
commit(CommitContext)- сохраняет в базе данных набор сущностей, переданный в объектеCommitContext. Отдельно указываются коллекции сущностей, которые нужно сохранить и которые нужно удалить.Метод возвращает набор экземпляров сущностей, возвращенных из метода EntityManager.merge(), то есть по сути свежие экземпляры, только что обновленные в БД. Дальнейшая работа должна производиться именно с этими возвращенными экземплярами, чтобы предотвратить потерю данных или исключения оптимистичной блокировки. Для того, чтобы обеспечить наличие нужных атрибутов у возвращенных сущностей, с помощью мэп
CommitContext.getViews()можно указать представление для каждого сохраняемого экземпляра.Примеры сохранения коллекций сущностей:
@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(Entity, View)- удобный метод для перезагрузки экземпляра сущности с требуемым представлением. Делегирует выполнение методуload(). -
remove(Entity)- удаляет экземпляр сущности из базы данных. Делегирует выполнение методуcommit(). -
create(Class)- создает экземпляр данной сущности в памяти. Этот метод просто делегирует вMetadata.create(). -
getReference(Class, Object)- возвращает экземпляр сущности, который может быть использован в качестве ссылки на объект, существующий в базе данных.Например, если вы создаете экземпляр сущности
User, вам необходимо установить ссылку наGroup, в которую данный пользователь будет входить. Если вам известен id группы, то вы могли бы загрузить данную группу из БД. Данный метод позволяет получить экземплярGroupбез ненужного обращения к БД:user.setGroup(dataManager.getReference(Group.class, groupId)); dataManager.commit(user);Ссылка может также быть использована для удаления существующего объекта по идентификатору:
dataManager.remove(dataManager.getReference(Customer.class, customerId));
- Запросы
-
Правила создания запросов аналогичны описанным в разделе Выполнение JPQL-запросов. Отличием является то, что в запросе, выполняемом через
DataManager, могут быть использованы только именованные параметры, позиционные не поддерживаются.
- Транзакции
-
DataManagerвсегда стартует новую транзакцию и по завершении работы выполняет коммит, таким образом возвращая сущности в detached состоянии.
- Частичные сущности
-
Частичная сущность - это экземпляр сущности, в котором может быть загружена только часть локальных атрибутов. По умолчанию, DataManager загружает частичные сущности в соответствии с указанными представлениями. (на самом деле,
RdbmsStoreпросто устанавливает свойство loadPartialEntities у представления в true и передает его дальше в EntityManager).В некоторых случаях DataManager загружает все локальные атрибуты и представление определяет только загрузку связей:
-
Загружаемая сущность кэшируется.
-
Для сущности заданы in-memory "read" ограничения.
-
Для сущности задан динамический контроль доступа к атрибутам.
-
Атрибут
loadPartialEntitiesобъектаLoadContextустановлен в false.
-