Рассмотрим реализацию композиции на примере сущностей Airport
и Terminal
:
-
Сущность
Terminal
содержит обязательную ссылку наAirport
:@Entity(name = "sample$Terminal") @Table(name = "SAMPLE_TERMINAL") public class Terminal extends StandardEntity { ... @ManyToOne(optional = false, fetch = FetchType.LAZY) @JoinColumn(name = "AIRPORT_ID") private Airport airport; public Airport getAirport() { return airport; } public void setAirport(Airport airport) { this.airport = airport; } }
-
Сущность
Airport
содержит one-to-many коллекцию терминалов. Соответствующее поле помечается аннотацией @Composition для огранизации композиции и @OnDelete для каскадного мягкого удаления:@Entity(name = "sample$Airport") @Table(name = "SAMPLE_AIRPORT") public class Airport extends StandardEntity { ... @OneToMany(fetch = FetchType.LAZY, mappedBy = "airport") @OnDelete(DeletePolicy.CASCADE) @Composition protected List<Terminal> terminals; public List<Terminal> getTerminals() { return terminals; } public void setTerminals(List<Terminal> terminals) { this.terminals = terminals; } }
-
Представление, используемое в экране редактирования аэропорта, должно содержать атрибут-коллецию
terminals
:<view entity="sample$Airport" name="airport-edit" extends="_local"> <property name="terminals" view="_local"/> </view>
Для сущности
Terminal
здесь выбрано представление_local
, хотя она содержит ссылочный атрибутairport
- ссылку на аэропорт. Дело в том, что атрибутairport
устанавливается только при создании нового экземпляраTerminal
, и не меняется в дальнейшем, поэтому загружать его не обязательно. -
В XML-дескрипторе экрана редактирования аэропорта определяем источники данных для экземпляра
Airport
и коллекции его терминалов:<dsContext> <datasource id="airportDs" class="com.haulmont.sample.entity.Airport" view="airport-edit"> <collectionDatasource id="terminalsDs" property="terminals"/> </datasource> </dsContext>
-
В XML-дескрипторе экрана редактирования аэропорта определяем таблицу, отображающую терминалы, и стандартные действия для нее:
<table id="terminalsTable"> <actions> <action id="create"/> <action id="edit"/> <action id="remove"/> </actions> <buttonsPanel> <button action="terminalsTable.create"/> <button action="terminalsTable.edit"/> <button action="terminalsTable.remove"/> </buttonsPanel> <columns> <column id="code"/> <column id="name"/> <column id="address"/> </columns> <rows datasource="terminalsDs"/> </table>
-
В экране редактирования терминала достаточно определить стандартные элементы:
datasource
для экземпляраTerminal
и визуальные компоненты, связанные с этимdatasource
, для редактирования атрибутов терминала.
В результате редактирование экземпляра аэропорта работает следующим образом:
-
В экране редактирования аэропорта отображается таблица терминалов.
-
Пользователь может выбрать терминал и открыть экран его редактирования. При нажатии
в экране редактирования терминала измененный экземпляр терминала сохраняется не в базу данных, а в источник данныхterminalsDs
экрана редактирования аэропорта. -
Пользователь может создавать новые или удалять терминалы - все изменения сохраняются в источнике данных
terminalsDs
. -
Пользователь нажимает
в экране редактирования аэропорта, и измененныйAirport
вместе со всеми измененными экземплярамиTerminal
отправляется на Middleware в метод DataManager.commit() и сохраняется в базе данных в рамках одной транзакции.