5.8.3.1. Implementing a Composition
Let us implement a composition using the Airport and the Terminal entities as an example:
-
The
Terminalentity contains a mandatory link to theAirport:@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; } } -
The
Airportentity contains one-to-many collection of terminals. The corresponding field is annotated with @Composition in order to implement composition, and @OnDelete for cascaded soft delete:@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; } } -
The view of the airport editing screen should contain the
terminalsattributes collection:<view entity="sample$Airport" name="airport-edit" extends="_local"> <property name="terminals" view="_local"/> </view>For the
Terminalentity, we are using the_localview, although it contains theairportlink attribute (a link to an airport). Theairportattribute is set only at the creation of a newTerminalinstance and never changes after that, so we do not need to load it. -
Next, we define the datasources for the
Airportinstance and its terminals in the XML descriptor of the airport editor:<dsContext> <datasource id="airportDs" class="com.haulmont.sample.entity.Airport" view="airport-edit"> <collectionDatasource id="terminalsDs" property="terminals"/> </datasource> </dsContext> -
Define a table displaying terminals and standard actions for it in the XML descriptor of the airport editor:
<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> -
It is sufficient to define the standard elements in the terminal editor:
datasourcefor theTerminalinstance and visual components related to thisdatasourcefor editing terminal attributes.
As a result, editing of an airport instance works as follows:
-
The airport edit screen shows a list of terminals.
-
A user can pick a terminal and open its editor. When OK is clicked in the terminal editor, the updated instance of the terminal is not saved to the database, but to the
terminalsDsdatasource of the airport editor. -
The user can create new terminals and delete existing ones. All changes will be saved to the
terminalsDsdatasource. -
When a user clicks OK in the airport edit screen, the updated
Airportinstance together with all the updatedTerminalinstances is submitted to the DataManager.commit() method on the Middleware and saved in the database within a single transaction.