Add support in JHipster Domain Language (JDL) for modeling composite primary keys
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