Журнал сущностей
Журнал сущностей - это механизм для отслеживания изменений, вносимых в JPA-сущности. Он фиксирует изменения атрибутов сущностей и предоставляет пользовательский интерфейс для запроса и отображения деталей изменений:
-
Какая сущность была изменена.
-
Старые и новые значения измененных атрибутов.
-
Когда сущность была изменена.
-
Какой пользователь изменил сущность.
Регистрация изменений
Журнал сущностей автоматически фиксирует изменения, вносимые в JPA-сущности при коммите транзакции при работе с DataManager или EntityManager. Он не функционирует при использовании нативного SQL.
Также, если вы загружаете сущности через EntityManager
, вы можете использовать бин EntityLog
напрямую для регистрации изменений в сущностях из кода вашего приложения. В этом случае вызывайте методы registerCreate()
, registerModify()
и registerDelete()
с параметром auto
, установленным в false
. Когда журнал сущностей вызывается фреймворком автоматически, этот параметр устанавливается в true
.
Настройка журнала сущностей
Для использования административного интерфейса во время выполнения пользователь должен иметь ресурсную роль entity-log , предоставляемую дополнением Audit.
|
Вы можете настроить журнал сущностей в экране Audit → Entity log. Перейдите на вкладку Setup:

Чтобы создать конфигурацию журнала сущностей, нажмите кнопку Create.
-
Выберите сущность из выпадающего списка Name и выберите атрибуты для аудита.
-
Флажок Auto определяет, регистрирует ли система изменения, когда
EntityLog
вызывается подсистемой JPA при коммите транзакции (с параметромauto = true
). -
Флажок Manual определяет, регистрирует ли система изменения, когда
EntityLog
вызывается кодом приложения (с параметромauto = false
). -
Действия Export и Import позволяют экспортировать и импортировать конфигурации в формате JSON или ZIP.
Также вы можете настроить журнал сущностей, добавив записи в базу данных, если хотите включить конфигурацию в инициализацию базы данных.
Конфигурация логирования включает сущности LoggedEntity
и LoggedAttribute
, которые соответствуют таблицам AUDIT_LOGGED_ENTITY
и AUDIT_LOGGED_ATTR
.
-
LoggedEntity
определяет типы сущностей, которые должны логироваться. -
LoggedAttribute
определяет атрибут сущности для логирования и содержит ссылку наLoggedEntity
и имя атрибута.
Чтобы настроить логирование для конкретной сущности, вставьте соответствующие записи в таблицы AUDIT_LOGGED_ENTITY
и AUDIT_LOGGED_ATTR
.
В следующем примере настройка логирования изменений атрибута phone
сущности Customer
выполняется во время инициализации базы данных:
<changeSet id="1" author="audit">
<insert tableName="AUDIT_LOGGED_ENTITY">
<column name="ID" value="0a6ba81c-a8b9-bc8f-3829-53a6cef48871"/>
<column name="CREATED_BY" value="admin"/>
<column name="CREATE_TS" valueDate="2024-02-21T14:57:25.339"/>
<column name="NAME" value="Customer"/>
<column name="AUTO" value="true"/>
<column name="MANUAL" value="true"/>
</insert>
</changeSet>
<changeSet id="2" author="audit">
<insert tableName="AUDIT_LOGGED_ATTR">
<column name="ID" value="8e6e9825-1381-5299-e704-eadf1b96996e"/>
<column name="CREATE_TS" valueDate="2024-02-21T14:57:25.339"/>
<column name="CREATED_BY" value="admin"/>
<column name="ENTITY_ID" value="0a6ba81c-a8b9-bc8f-3829-53a6cef48871"/>
<column name="NAME" value="phone"/>
</insert>
</changeSet>
Просмотр журнала сущностей
Для доступа к содержимому журнала сущностей перейдите на вкладку View в экране Audit → Entity Log. Настройте необходимые фильтры для поиска конкретных записей журнала.

Дополнительно вы можете получить доступ к записям журнала для конкретной сущности из любого экрана приложения.
Записи журнала хранятся в таблице AUDIT_ENTITY_LOG
, соответствующей сущности EntityLogItem
. Значения измененных атрибутов хранятся в колонке CHANGES
и конвертируются в экземпляры сущности EntityLogAttr
.
В следующем примере экран деталей сущности Order
отображает таблицы данных, содержащие информацию журнала сущностей. Ниже приведен фрагмент XML-дескриптора экрана:
<data>
<instance id="orderDc"
class="com.company.demo.entity.Order">
<fetchPlan extends="_base"/>
<loader/>
</instance>
<collection id="entityLogItemsDc"
class="io.jmix.audit.entity.EntityLogItem"> (1)
<fetchPlan extends="_local"/>
<loader id="entityLogItemsDl" readOnly="true">
<query>
<![CDATA[select e from audit_EntityLog e
where e.entityRef.entityId = :entityOrder]]>
</query>
</loader>
<collection id="entityLogAttrDc" property="attributes"/> (2)
</collection>
</data>
<facets>
<dataLoadCoordinator auto="true"/>
</facets>
<actions>
<action id="saveAction" type="detail_saveClose"/>
<action id="closeAction" type="detail_close"/>
</actions>
<layout>
<formLayout id="form" dataContainer="orderDc">
<datePicker id="dateField" property="date"/>
<textField id="productField" property="product"/>
<textField id="amountField" property="amount"/>
<textField id="priceField" property="price"/>
</formLayout>
<formLayout>
<dataGrid id="entityLogItemsDataGrid"
dataContainer="entityLogItemsDc"> (3)
<columns>
<column property="eventTs"/>
<column property="username"/>
<column property="type"/>
</columns>
</dataGrid>
<dataGrid id="entityLogAttrsDataGrid"
dataContainer="entityLogAttrDc"> (4)
<columns>
<column property="name"/>
<column property="oldValue"/>
<column property="value"/>
</columns>
</dataGrid>
</formLayout>
<hbox id="detailActions">
<button id="saveAndCloseBtn" action="saveAction"/>
<button id="closeBtn" action="closeAction"/>
</hbox>
</layout>
1 | Загрузка коллекции EntityLogItem в контейнер данных entityLogItemsDc . |
2 | Загрузка связанных экземпляров EntityLogAttr в контейнер данных entityLogAttrDc . |
3 | Привязка таблицы данных к контейнеру entityLogItemsDc . |
4 | Привязка таблицы данных к контейнеру entityLogAttrDc . |
Контроллер экрана Order
выглядит следующим образом:
@ViewComponent
private CollectionLoader<EntityLogItem> entityLogItemsDl;
@Subscribe(id = "orderDc", target = Target.DATA_CONTAINER)
public void onOrderDcItemChange(final InstanceContainer.ItemChangeEvent<Order> event) { (1)
entityLogItemsDl.setParameter("entityOrder",event.getItem().getId());
entityLogItemsDl.load();
}
1 | В обработчике события ItemChangeEvent контейнера orderDc параметр устанавливается в зависимый загрузчик, и он запускается. |