Model linking provides the mechanism for establishing master-detail relationships between entity models. The framework automatically synchronizes detail models based on master model selection and data changes.

1. Overview

The ModelLink API enables automatic detail model filtering based on master selection and propagation of data changes.

    // Invoice -> InvoiceLines
    SwingEntityModel invoiceModel = new SwingEntityModel(Invoice.TYPE, connectionProvider);
    SwingEntityModel invoiceLineModel = new SwingEntityModel(InvoiceLine.TYPE, connectionProvider);

    invoiceModel.detailModels().add(invoiceLineModel);

    // Configure detail model for optimal performance
    invoiceLineModel.tableModel().queryModel().conditionRequired().set(true); // Don't load all lines
    invoiceLineModel.tableModel().queryModel().limit().set(1000); // Reasonable limit

Create links with specific behavior:

    SwingEntityModel customerModel = new SwingEntityModel(Customer.TYPE, connectionProvider);
    SwingEntityModel invoiceModel = new SwingEntityModel(Invoice.TYPE, connectionProvider);

    ModelLink<SwingEntityModel, SwingEntityEditModel, SwingEntityTableModel> customLink =
            customerModel.link(invoiceModel)
                    .active(true)
                    .onSelection(selectedCustomers -> {
                      // Custom selection logic
                      if (selectedCustomers.size() > 1) {
                        // Handle multi-selection differently
                        invoiceModel.tableModel().queryModel().condition().clear();
                        invoiceModel.tableModel().queryModel().where().set(() ->
                                Invoice.CUSTOMER_FK.in(selectedCustomers)
                        );
                      }
                    })
                    .build();

    customerModel.detailModels().add(customLink);

3. Automatic Foreign Key Management

The ForeignKeyModelLink specializes ModelLink for foreign key relationships:

    SwingEntityModel customerModel = new SwingEntityModel(Customer.TYPE, connectionProvider);
    SwingEntityModel invoiceModel = new SwingEntityModel(Invoice.TYPE, connectionProvider);

    // ForeignKeyModelLink is created automatically when foreign key is detected
    customerModel.detailModels().add(invoiceModel);

    // Or configure explicitly
    customerModel.detailModels().add(ForeignKeyModelLink.builder(invoiceModel, Invoice.CUSTOMER_FK)
            // Clear foreign key value when master has no selection
            .clearValueOnEmptySelection(true)
            // Set foreign key value automatically on insert
            .setValueOnInsert(true)
            // Control when to refresh detail data
            .refreshOnSelection(true)
            // Filter detail records based on master selection
            .setConditionOnInsert(true)
            .build());

4. Simple One-to-Many

Classic master-detail relationship:

    // Invoice -> InvoiceLines
    SwingEntityModel invoiceModel = new SwingEntityModel(Invoice.TYPE, connectionProvider);
    SwingEntityModel invoiceLineModel = new SwingEntityModel(InvoiceLine.TYPE, connectionProvider);

    invoiceModel.detailModels().add(invoiceLineModel);

    // Configure detail model for optimal performance
    invoiceLineModel.tableModel().queryModel().conditionRequired().set(true); // Don't load all lines
    invoiceLineModel.tableModel().queryModel().limit().set(1000); // Reasonable limit

5. Multi-Level Hierarchy

Deep master-detail chains:

    // Customer -> Invoice -> InvoiceLine
    SwingEntityModel customerModel = new SwingEntityModel(Customer.TYPE, connectionProvider);
    SwingEntityModel invoiceModel = new SwingEntityModel(Invoice.TYPE, connectionProvider);
    SwingEntityModel invoiceLineModel = new SwingEntityModel(InvoiceLine.TYPE, connectionProvider);

    // Build hierarchy
    customerModel.detailModels().add(invoiceModel);
    invoiceModel.detailModels().add(invoiceLineModel);

    // Configure each level
    invoiceModel.tableModel().queryModel().conditionRequired().set(true);
    invoiceLineModel.tableModel().queryModel().conditionRequired().set(true);

    // Selection cascades down the hierarchy automatically
    Entity customer = getCustomer(connectionProvider);
    customerModel.tableModel().selection().item().set(customer);
    // Invoices for customer are loaded
    // When an invoice is selected, its lines are loaded
    invoiceModel.tableModel().selection().indexes().increment();// selects first