5.8.3.1. Implementing a Composition
Let us implement a composition using the Airport
and the Terminal
entities as an example:
-
The
Terminal
entity 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
Airport
entity 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
terminals
attributes collection:<view entity="sample$Airport" name="airport-edit" extends="_local"> <property name="terminals" view="_local"/> </view>
For the
Terminal
entity, we are using the_local
view, although it contains theairport
link attribute (a link to an airport). Theairport
attribute is set only at the creation of a newTerminal
instance and never changes after that, so we do not need to load it. -
Next, we define the datasources for the
Airport
instance 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:
datasource
for theTerminal
instance and visual components related to thisdatasource
for 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
terminalsDs
datasource of the airport editor. -
The user can create new terminals and delete existing ones. All changes will be saved to the
terminalsDs
datasource. -
When a user clicks OK in the airport edit screen, the updated
Airport
instance together with all the updatedTerminal
instances is submitted to the DataManager.commit() method on the Middleware and saved in the database within a single transaction.