The EntityQueryModel manages how entities are fetched from the database for table models. It provides fine-grained control over query conditions, result limits, ordering, and custom data sources.

1. Overview

EntityQueryModel acts as the data retrieval engine for EntityTableModel, encapsulating:

  • Query conditions (WHERE and HAVING clauses)

  • Result limits to prevent excessive data loading

  • Custom ordering specifications

  • Attribute selection for optimization

  • Custom data sources for specialized queries

    SwingEntityModel customerModel = new SwingEntityModel(Customer.TYPE, connectionProvider);
    SwingEntityTableModel tableModel = customerModel.tableModel();
    EntityQueryModel queryModel = tableModel.queryModel();

    // Configure query behavior
    queryModel.limit().set(200);
    queryModel.conditionRequired().set(true);
    queryModel.orderBy().set(OrderBy.ascending(Customer.LASTNAME));

2. Condition Management

2.1. Table Condition Model

The primary condition mechanism is the EntityTableConditionModel, which provides a flexible way to build complex queries:

    SwingEntityModel customerModel = new SwingEntityModel(Customer.TYPE, connectionProvider);
    EntityTableConditionModel conditionModel = customerModel.tableModel().queryModel().condition();

    // Set condition values
    conditionModel.get(Customer.EMAIL).set().isNotNull();
    conditionModel.get(Customer.COUNTRY).set().equalTo("Iceland");

    // The resulting query will include:
    // WHERE email is not null AND country = 'Iceland'

2.2. Additional WHERE Conditions

Beyond the table condition model, you can add custom WHERE conditions:

    SwingEntityModel customerModel = new SwingEntityModel(Customer.TYPE, connectionProvider);
    EntityQueryModel queryModel = customerModel.tableModel().queryModel();

    // Single additional condition
    queryModel.where().conjunction().set(Conjunction.AND);
    queryModel.where().set(() -> Customer.COUNTRY.equalTo("Iceland"));

    // Multiple conditions with custom conjunction
    queryModel.where().set(() -> Condition.or(
            Customer.CITY.equalTo("Reykjavik"),
            Customer.CITY.equalTo("Akureyri")
    ));

3. Query Limits

Prevent loading excessive data by setting query limits:

    SwingEntityModel customerModel = new SwingEntityModel(Customer.TYPE, connectionProvider);
    EntityQueryModel queryModel = customerModel.tableModel().queryModel();

    // Set a specific limit
    queryModel.limit().set(500);

    // Remove limit (fetch all matching rows)
    queryModel.limit().clear();

    // Add a max limit validator
    queryModel.limit().addValidator(newLimit -> {
      if (newLimit > 10.000) {
        throw new IllegalArgumentException("Limit may not exceed 10.000");
      }
    });

    // Listen for limit changes
    queryModel.limit().addConsumer(newLimit ->
            System.out.println("Query limit changed to: " + newLimit));

4. Result Ordering

Specify how results should be ordered:

    SwingEntityModel invoiceModel = new SwingEntityModel(Invoice.TYPE, connectionProvider);
    EntityQueryModel queryModel = invoiceModel.tableModel().queryModel();

    // Single column ordering
    queryModel.orderBy().set(OrderBy.descending(Invoice.DATE));

    // Multiple columns
    queryModel.orderBy().set(OrderBy.builder()
            .ascending(Invoice.BILLINGCOUNTRY)
            .descending(Invoice.DATE)
            .build()
    );

5. Custom Data Sources

For complex queries that can’t be expressed through conditions, provide a custom data source:

    SwingEntityModel customerModel = new SwingEntityModel(Customer.TYPE, connectionProvider);
    EntityQueryModel entityQueryModel = customerModel.tableModel().queryModel();

    entityQueryModel.dataSource().set(queryModel -> {
      EntityConnection connection = queryModel.connectionProvider().connection();

      // Custom query with complex joins or database-specific features
      return connection.select(Select.where(customComplexCondition())
              .attributes(Customer.ADDRESS, Customer.CITY, Customer.COUNTRY)
              .build());
    });

6. Condition Required

Prevent accidental full table scans:

    SwingEntityModel customerModel = new SwingEntityModel(Customer.TYPE, connectionProvider);
    EntityQueryModel queryModel = customerModel.tableModel().queryModel();

    // Require at least one condition
    queryModel.conditionRequired().set(true);

    // Specify that a certain condition must be enabled
    queryModel.conditionEnabled().set(queryModel.condition().get(Customer.SUPPORTREP_FK).enabled());

7. Attribute Management

Optimize queries by selecting only needed attributes:

    SwingEntityModel albumModel = new SwingEntityModel(Album.TYPE, connectionProvider);
    EntityQueryModel queryModel = albumModel.tableModel().queryModel();

    // Exclude large columns by default
    queryModel.attributes().excluded().add(Album.COVER);

    // Include them only when needed
    State detailView = State.state();
    detailView.addConsumer(showDetails -> {
      if (showDetails) {
        queryModel.attributes().included().add(Album.COVER);
      }
    });

8. Configuration Properties

Table 1. EntityQueryModel Configuration
Property Default Description

is.codion.framework.model.EntityTableModel.LIMIT

1000

Default query limit

is.codion.framework.model.EntityTableModel.CONDITION_REQUIRED

false

Whether queries require at least one condition

is.codion.framework.model.EntityQueryModel.SELECT_ATTRIBUTES

empty

Default attributes to exclude from queries