Search code examples
cuba-platform

CUBA : entity inheritance


Provided sample 'Entity Inheritance' has the following entity model:
- Customer
- Company extends Customer
- Person extends Customer
- Order

The OrderEdit screen show how to handle the inheritance for fields associated with a Customer that could be a Company or a Person. This is perfectly clear.

However, edit screens for Company and Person do not take inheritance into account : they simply duplicate 'email' field which is commonly inherited from Customer.

Given all inputs I had at this point, if I had to design these screens I would propose the following way.

1) CustomerEditFrame : with the email field, no datasource defined

2) PersonEditScreen:
- Person datasource
- map lastName and firstName fields on Person datasource
- embed CustomerEditFrame
- inject Person datasource in the CustomerEditFrame

3) CompanyEditScreen:
- Company datasource
- map industry field to Company datasource
- embed CustomerEditFrame
- inject Company datasource in the CustomerEditFrame

Then the CustomerEditFrame is responsible for editing the subset of fields it is aware of in a datasource referring either of the two subclasses. Would this design work ?

For the sake of completeness of documentation I think this should be covered by the sample, as it is common case. In addition, it would be a good sample for frame manipulation.


Solution

  • You are absolutely right that screens should take entity inheritance into account to eliminate duplication of code. I've forked the sample project here to demonstrate how it can be done using frames.

    customer-frame.xml contains fields of the base entity and a datasource for it:

    <window xmlns="http://schemas.haulmont.com/cuba/window.xsd"
            caption="msg://editCaption"
            class="com.company.entityinheritance.gui.customer.CustomerFrame"
            focusComponent="fieldGroup"
            messagesPack="com.company.entityinheritance.gui.customer">
        <dsContext>
            <datasource id="customerDs"
                        class="com.company.entityinheritance.entity.Customer"
                        view="_local"/>
        </dsContext>
        <layout spacing="true">
            <fieldGroup id="fieldGroup"
                        datasource="customerDs">
                <column width="250px">
                    <field id="name"/>
                    <field id="email"/>
                </column>
            </fieldGroup>
        </layout>
    </window>
    

    In the CustomerFrame controller there is a public method to set an instance to the datasource:

    public class CustomerFrame extends AbstractFrame {
    
        @Inject
        private Datasource<Customer> customerDs;
    
        public void setCustomer(Customer customer) {
            customerDs.setItem(customer);
        }
    }
    

    The Company editor company-edit.xml includes the frame instead of Customer fields:

    <window xmlns="http://schemas.haulmont.com/cuba/window.xsd"
            caption="msg://editCaption"
            class="com.company.entityinheritance.gui.company.CompanyEdit"
            datasource="companyDs"
            focusComponent="customerFrame"
            messagesPack="com.company.entityinheritance.gui.company">
        <dsContext>
            <datasource id="companyDs"
                        class="com.company.entityinheritance.entity.Company"
                        view="_local"/>
        </dsContext>
        <layout expand="windowActions"
                spacing="true">
            <frame id="customerFrame"
                   screen="demo$Customer.frame"/>
            <fieldGroup id="fieldGroup"
                        datasource="companyDs">
                <column width="250px">
                    <field id="industry"/>
                </column>
            </fieldGroup>
            <frame id="windowActions"
                   screen="editWindowActions"/>
        </layout>
    </window>
    

    In the Company editor controller, the frame is injected and an edited instance is passed to it:

    public class CompanyEdit extends AbstractEditor<Company> {
    
        @Inject
        private CustomerFrame customerFrame;
    
        @Override
        protected void postInit() {
            customerFrame.setCustomer(getItem());
        }
    }