Interface KeyGenerator

All Known Subinterfaces:
KeyGenerator.Identity

public interface KeyGenerator
Generates primary key values for entities on insert.

KeyGenerators fall into two categories:

  1. Pre-insert generators - Fetch or generate the primary key value before the row is inserted
  2. Post-insert generators - The database automatically sets the primary key value on insert (identity columns, triggers)

Implementations should override either beforeInsert() or afterInsert():

Common key generator types and usage patterns:

public class Store extends DefaultDomain {

    interface Customer {
        EntityType TYPE = DOMAIN.entityType("store.customer");
        Column<Integer> ID = TYPE.integerColumn("id");
    }

    interface Product {
        EntityType TYPE = DOMAIN.entityType("store.product");
        Column<Long> ID = TYPE.longColumn("id");
    }

    interface Order {
        EntityType TYPE = DOMAIN.entityType("store.order");
        Column<String> ID = TYPE.stringColumn("id");
    }

    void defineEntities() {
        // Identity column (database auto-increment)
        Customer.TYPE.define(
                Customer.ID.define()
                    .primaryKey()
                    .keyGenerator(KeyGenerator.identity()))
            .build();

        // Sequence-based key generation (Oracle, PostgreSQL)
        Product.TYPE.define(
                Product.ID.define()
                    .primaryKey()
                    .keyGenerator(KeyGenerator.sequence("product_seq")))
            .build();

        // Custom query-based key generation
        Order.TYPE.define(
                Order.ID.define()
                    .primaryKey()
                    .keyGenerator(KeyGenerator.queried("SELECT 'ORD-' || NEXT VALUE FOR order_seq")))
            .build();
    }
}

// Custom key generator implementation
public class UUIDKeyGenerator implements KeyGenerator {

    @Override
    public void beforeInsert(Entity entity, DatabaseConnection connection) {
        // Only generate if not already set
        if (entity.primaryKey().isNull()) {
            String uuid = UUID.randomUUID().toString();
            entity.set(MyEntity.ID, uuid);
        }
    }

    @Override
    public boolean inserted() {
        return true; // Include generated key in INSERT
    }
}
See Also:
  • Nested Class Summary

    Nested Classes
    Modifier and Type
    Interface
    Description
    static interface 
    Marker interface indicating that a key generator is based on an identity column.
  • Method Summary

    Modifier and Type
    Method
    Description
    default void
    afterInsert(Entity entity, DatabaseConnection connection, Statement insertStatement)
    Prepares the given entity after insert, that is, fetches automatically generated primary key values and populates the entity's primary key.
    automatic(String valueSource)
    Instantiates a primary key generator which fetches automatically incremented primary key values after insert.
    default void
    beforeInsert(Entity entity, DatabaseConnection connection)
    Prepares the given entity for insert, that is, generates and fetches any required primary key values and populates the entity's primary key.
    Returns a primary key generator based on an IDENTITY type column.
    default boolean
    The default implementation returns true.
    queried(String query)
    Instantiates a primary key generator which fetches primary key values using the given query prior to insert.
    default boolean
    Specifies whether the insert statement should return the primary key column values via the resulting Statement.getGeneratedKeys() resultSet, accessible in afterInsert(Entity, DatabaseConnection, Statement).
    sequence(String sequenceName)
    Instantiates a primary key generator which fetches primary key values from a sequence prior to insert.
  • Method Details

    • inserted

      default boolean inserted()
      The default implementation returns true.
      Returns:
      true if the primary key value should be included in the insert query when entities using this key generator is inserted
    • beforeInsert

      default void beforeInsert(Entity entity, DatabaseConnection connection) throws SQLException
      Prepares the given entity for insert, that is, generates and fetches any required primary key values and populates the entity's primary key. The default implementation does nothing, override to implement.
      Parameters:
      entity - the entity about to be inserted
      connection - the connection to use
      Throws:
      SQLException - in case of an exception
    • afterInsert

      default void afterInsert(Entity entity, DatabaseConnection connection, Statement insertStatement) throws SQLException
      Prepares the given entity after insert, that is, fetches automatically generated primary key values and populates the entity's primary key. The default implementation does nothing, override to implement.
      Parameters:
      entity - the inserted entity
      connection - the connection to use
      insertStatement - the insert statement
      Throws:
      SQLException - in case of an exception
    • returnGeneratedKeys

      default boolean returnGeneratedKeys()
      Specifies whether the insert statement should return the primary key column values via the resulting Statement.getGeneratedKeys() resultSet, accessible in afterInsert(Entity, DatabaseConnection, Statement). The default implementation returns false.
      Returns:
      true if the primary key column values should be returned via the insert statement resultSet
      See Also:
    • sequence

      static KeyGenerator sequence(String sequenceName)
      Instantiates a primary key generator which fetches primary key values from a sequence prior to insert. Note that if the primary key value of the entity being inserted is already populated this key generator does nothing, that is, it does not overwrite a manually set primary key value.
      // Oracle or PostgreSQL sequence
      Product.TYPE.define(
              Product.ID.define()
                  .primaryKey()
                  .keyGenerator(KeyGenerator.sequence("product_seq")))
          .build();
      
      // Usage - key is generated automatically
      Entity product = entities.builder(Product.TYPE)
          .with(Product.NAME, "Laptop")
          .with(Product.PRICE, new BigDecimal("999.99"))
          .build();
      
      // Primary key will be fetched from sequence before insert
      connection.insert(product);
      Long generatedId = product.get(Product.ID); // e.g., 123
      
      // Manual key override (sequence not used)
      Entity productWithManualId = entities.builder(Product.TYPE)
          .with(Product.ID, 999L) // Explicitly set
          .with(Product.NAME, "Special Product")
          .build();
      
      connection.insert(productWithManualId); // Uses ID 999, not sequence
      
      Parameters:
      sequenceName - the sequence name
      Returns:
      a sequence based primary key generator
    • queried

      static KeyGenerator queried(String query)
      Instantiates a primary key generator which fetches primary key values using the given query prior to insert. Note that if the primary key value of the entity being inserted is already populated this key generator does nothing, that is, it does not overwrite a manually set primary key value.
      // Custom query-based key generation
      Order.TYPE.define(
              Order.ID.define()
                  .primaryKey()
                  .keyGenerator(KeyGenerator.queried("SELECT 'ORD-' || NEXT VALUE FOR order_seq")))
          .build();
      
      // Another example with date-based keys
      Invoice.TYPE.define(
              Invoice.ID.define()
                  .primaryKey()
                  .keyGenerator(KeyGenerator.queried(
                      "SELECT FORMAT(GETDATE(), 'yyyyMMdd') + '-' + RIGHT('0000' + CAST(NEXT VALUE FOR invoice_seq AS VARCHAR), 4)")))
          .build();
      
      // Usage
      Entity order = entities.builder(Order.TYPE)
          .with(Order.CUSTOMER_FK, customer)
          .with(Order.TOTAL, new BigDecimal("150.00"))
          .build();
      
      connection.insert(order);
      String generatedId = order.get(Order.ID); // e.g., "ORD-12345"
      
      Parameters:
      query - a query for retrieving the primary key value
      Returns:
      a query based primary key generator
    • automatic

      static KeyGenerator automatic(String valueSource)
      Instantiates a primary key generator which fetches automatically incremented primary key values after insert.
      Parameters:
      valueSource - the value source, whether a sequence or a table name
      Returns:
      an auto-increment based primary key generator
    • identity

      static KeyGenerator.Identity identity()
      Returns a primary key generator based on an IDENTITY type column.
      // SQL Server, MySQL auto-increment, or similar
      Customer.TYPE.define(
              Customer.ID.define()
                  .primaryKey()
                  .keyGenerator(KeyGenerator.identity()))
          .build();
      
      // Usage - database generates the key
      Entity customer = entities.builder(Customer.TYPE)
          .with(Customer.NAME, "John Doe")
          .with(Customer.EMAIL, "john@example.com")
          .build();
      
      // Primary key is null before insert
      Integer idBeforeInsert = customer.get(Customer.ID); // null
      
      // Database auto-generates the key during insert
      connection.insert(customer);
      
      // Primary key is now populated from database
      Integer generatedId = customer.get(Customer.ID); // e.g., 42
      
      Returns:
      a generated primary key generator
      See Also: