Add support in JHipster Domain Language (JDL) for modeling composite primary keys

Author: vw98075Created May 11, 2026Updated Jul 17, 2026
Labelsarea: triagetheme: undefined
Overview of the feature request

Add support in JHipster Domain Language (JDL) for modeling composite primary keys (i.e., primary keys made up of multiple columns) using standard JPA patterns:

@IdClass (composite key represented by a separate key class), and/or @EmbeddedId (composite key represented as an embeddable key object) This should allow users to express composite keys directly in JDL and have JHipster generate the correct JPA annotations, key classes, and equality semantics.

Right now, users who need composite PKs must resort to manual code changes after generation (which are easy to lose on re-generation), or choose suboptimal modeling approaches (e.g., adding surrogate IDs).

Motivation for or Use Case

Composite primary keys are common and sometimes domain-correct for:

Join/association entities with identity

Many-to-many implemented as an explicit entity (e.g., OrderLine / Enrollment) where identity is naturally (orderId, lineNumber) or (userId, courseId). In these cases, adding a surrogate UUID id is often undesirable. Legacy databases and existing schemas

When integrating with pre-existing schemas, composite keys are often the norm. Without JDL support, users must patch generated code and re-run migrations/DDL carefully. Uniqueness defined by business keys

Some domains define uniqueness as a combination of multiple attributes (e.g., TenantId + ExternalReference). Correctness and performance

Composite PKs can better express invariants and can reduce additional indexes created for surrogate keys. Maintainability

First-class JDL support avoids fragile “generate then edit” workflows and improves regeneration safety.

Proposed JDL syntax (example) This is one possible way to express composite keys. You can adjust to match JHipster’s preferred DSL style.

Option A: Specify multiple primaryKey fields per entity

entity OrderLine {
  orderId Long primaryKey
  lineNumber Integer primaryKey
  productCode String
  quantity Integer
}

Expected generation:

A composite key definition using either @IdClass or @EmbeddedId orderId and lineNumber part of the PK Correct getters/setters and equals/hashCode on the key type Option B: Explicit key type (more explicit, closer to JPA)

embeddable OrderLineKey {
  orderId Long
  lineNumber Integer
}

entity OrderLine {
  id OrderLineKey primaryKey
  productCode String
  quantity Integer
}

Expected generation:

OrderLineKey annotated with @Embeddable OrderLine.id annotated with @EmbeddedId Column mapping consistent with JDL naming conventions Acceptance criteria / expected behavior JDL can declare a composite primary key

Via multiple fields marked as part of the key, and/or via a dedicated key object. Correct JPA strategy is generated

Support at least one of: @IdClass, or @EmbeddedId Ideally allow a configuration switch or auto-select (e.g., prefer @EmbeddedId). Key classes/embeddables are generated

For @IdClass: generate the id class and ensure it contains the key fields. For @EmbeddedId: generate an @Embeddable key class. equals/hashCode are correct and consistent

Ensure both entity and key type behave correctly for persistence and collections. Column mapping is generated properly

Ensure each key field is mapped to columns with stable naming and no collisions. Relationships to composite-key entities work

If other entities reference the composite-key entity, JDL should generate valid mappings (as much as the chosen JPA strategy supports). Regeneration does not require manual edits

Generated code compiles and can be re-generated without breaking the composite key mappings. DTO generation remains coherent

The DTO should include composite key information in a consistent format (nested key object vs flattened fields), documented and stable. Notes / questions for implementation (optional) Should JDL default to @EmbeddedId (usually easier to keep encapsulated) or @IdClass? How should the column naming be handled when multiple PKs are embedded (prefixes/suffixes)? What is the expected DTO representation: nested id object (for @EmbeddedId), or flattened orderId, lineNumber fields?

Related issues or PR
  • Checking this box is mandatory (this is just to show you read everything)

Source: jhipster/generator-jhipster