kotlin-backend-jpa-entity-mapping
Skill2 starsChanged 31 days agoMITView on GitHub
Model Kotlin persistence code correctly for Spring Data JPA and Hibernate. Covers entity design, identity and equality, uniqueness constraints, relationships, fetch plans, and common ORM (Object-Relational Mapping) traps specific to Kotlin. Use when creating or reviewing JPA (Java Persistence API) entities, diagnosing N+1 or LazyInitializationException, placing indexes and uniqueness rules, or preventing Kotlin-specific bugs such as data class entities and broken equals/hashCode.
3 other projects use a version of this, 2 of them edited.
Adopted by
Most recently taken up by
- Kotlin/kotlin-agent-skillsedited, first seen Nov 1, 2026
- torad-labs/agent-driven-architectureword for word, first seen Oct 13, 2026
- JetBrains/skillsedited, first seen Apr 28, 2026
Other versions3 projects use a version of this.
Word for word · 1
- torad-labs/agent-driven-architecture★ 4100% same
Edited · 2
- Kotlin/kotlin-agent-skills★ 1.1k91% same
- JetBrains/skills★ 38697% same
Wrote their own version · 0
None found.
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository192 other files it gives its agents.
- clickhouse-architecture-advisor/AGENTS.mdAGENTS.md
- clickhouse-best-practices/AGENTS.mdAGENTS.md
- unsafe-checker/AGENTS.mdAGENTS.md
- alertmanager-querySkill
- analyzing-range-distributionSkill
- analyzing-schema-change-storage-riskSkill
- argocdSkill
- aspire-configurationSkill
- aspire-integration-testingSkill
- aspire-service-defaultsSkill
- auditing-cloud-cluster-securitySkill
- auditing-table-statisticsSkill
- benchmarking-transaction-patternsSkill
- cepthSkill
- chdb-datastoreSkill
- chdb-sqlSkill
- clickhouse-architecture-advisorSkill
- clickhouse-best-practicesSkill
- clickhousectl-cloud-deploySkill
- clickhousectl-local-devSkill
- cockroachdb-sqlSkill
- coding-guidelinesSkill
- configuring-audit-loggingSkill
- configuring-ip-allowlistsSkill
- configuring-log-exportSkill
- configuring-private-connectivitySkill
- configuring-sso-and-scimSkill
- create-technical-architecture-documentSkill
- csharp-mstestSkill
- csharp-tunitSkill
- csharp-xunitSkill
- designing-application-transactionsSkill
- designing-multi-region-applicationsSkill
- domain-cliSkill
- domain-cloud-nativeSkill
- domain-embeddedSkill
- domain-fintechSkill
- domain-iotSkill
- domain-mlSkill
- domain-webSkill
- dotnet-aot-wasmSkill
- dotnet-aspire-patternsSkill
- dotnet-benchmarkdotnetSkill
- dotnet-blazor-authSkill
- dotnet-blazor-componentsSkill
- dotnet-blazor-patternsSkill
- dotnet-blazor-testingSkill
- dotnet-channelsSkill
- dotnet-ci-benchmarkingSkill
- dotnet-cli-architectureSkill
- dotnet-cli-distributionSkill
- dotnet-cli-packagingSkill
- dotnet-cli-release-pipelineSkill
- dotnet-containersSkill
- dotnet-cryptographySkill
- dotnet-csharp-dependency-injectionSkill
- dotnet-csharp-modern-patternsSkill
- dotnet-csharp-nullable-reference-typesSkill
- dotnet-csharp-source-generatorsSkill
- dotnet-maui-doctorSkill
- The first 60 shown.
The file
Show its rules and text
We split this skill into the rules it gives an agent
16 rules. About 0 are common, 7 are distinctive, and 9 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈7
Distinctive · estimate
This author's own choices. Worth a look.
9
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 29
Never use
data classfor JPA entities: Use a regular class. Keep data class for DTOs. - Distinctive: line 30
Keep transport DTOs and persistence entities separate unless the project clearly uses a shared model.
- Very specific: line 32
Use lateinit only when the project already accepts that tradeoff and the lifecycle is safe.
- Very specific: line 33
Verify kotlin("plugin.jpa") or equivalent no-arg support when JPA entities exist.
- Distinctive: line 34
Verify classes and members are compatible with proxying where needed.
- Very specific: line 38
Never accept all-field equals/hashCode generated by data class on an entity.
- Distinctive: line 39
Follow project conventions when they already define an identity strategy.
- Very specific: line 40
If no convention exists, use ID-based equality with a stable hashCode.
- Distinctive: line 93
When an API must be idempotent (e.g., "reserve stock for order X"), enforce uniqueness at both layers: database constraint for correctness, …
- Very specific: line 160
Prefer targeted fetch solutions: @EntityGraph, JOIN FETCH, batch fetching, or DTO projection.
- Distinctive: line 162
Use indexes and uniqueness constraints to support real query patterns.
- Very specific: line 167
orphanRemovalvs cascade remove: not interchangeable. Explain lifecycle semantics before choosing. - Very specific: line 177
Do not use data class for JPA entities.
- Very specific: line 178
Do not recommend FetchType.EAGER everywhere to silence lazy loading symptoms.
- Distinctive: line 179
Do not expose entities directly through API responses by default.
- Distinctive: line 180
Do not claim an N+1 fix without explaining how the fetch plan changes query behavior.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
JPA Entity Mapping for Kotlin
Kotlin's data class is natural for DTOs but dangerous for JPA entities. Hibernate relies on
identity semantics that data class breaks: equals/hashCode over all fields corrupts
Set/Map membership after state changes, and auto-generated copy() creates detached
duplicates of managed entities.
This skill teaches correct entity design, identity strategies, and uniqueness constraints for Kotlin + Spring Data JPA projects.
Entity Design Rules
- Never use
data classfor JPA entities. Use a regularclass. Keepdata classfor DTOs. - Keep transport DTOs and persistence entities separate unless the project clearly uses a shared model.
- Model required columns as non-null only when object construction and persistence lifecycle make it safe.
- Use
lateinitonly when the project already accepts that tradeoff and the lifecycle is safe. - Verify
kotlin("plugin.jpa")or equivalent no-arg support when JPA entities exist. - Verify classes and members are compatible with proxying where needed.
Identity and Equality
- Never accept all-field
equals/hashCodegenerated bydata classon an entity. - Follow project conventions when they already define an identity strategy.
- If no convention exists, use ID-based equality with a stable
hashCode. - Be explicit about mutable fields and lazy associations when discussing equality.
Broken: data class Entity
// WRONG: data class generates equals/hashCode from ALL fields
data class Order(
@Id @GeneratedValue val id: Long = 0,
var status: String,
var total: BigDecimal
)
// BUG: order.status = "SHIPPED"; set.contains(order) → false (hash changed)
// BUG: Hibernate proxy.equals(entity) → false (proxy has lazy fields uninitialized)Correct: Regular Class with ID-Based Identity
@Entity
@Table(name = "orders")
class Order(
@Column(nullable = false)
var status: String,
@Column(nullable = false)
var total: BigDecimal
) {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long = 0
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is Order) return false
return id != 0L && id == other.id
}
override fun hashCode(): Int = javaClass.hashCode()
// toString must NOT reference lazy collections
override fun toString(): String = "Order(id=$id, status=$status)"
}Key rules:
equalscompares by ID only — stable under dirty tracking and proxy unwrappinghashCodereturns class-based constant — avoidsSet/Mapcorruption after persisttoStringexcludes lazy-loaded relations — preventsLazyInitializationException- Constructor params are mutable entity fields;
idisvalwith default
Uniqueness Constraints
When an API must be idempotent (e.g., "reserve stock for order X"), enforce uniqueness at both layers: database constraint for correctness, application check for clean errors.
Broken: No Duplicate Guard
@Service
class ReservationService(private val repo: ReservationRepository) {
@Transactional
fun createReservation(variantId: Long, orderId: String, qty: Int): Reservation {
// BUG: no check — duplicates silently accumulate
return repo.save(Reservation(variantId = variantId, orderId = orderId, quantity = qty))
}
}Correct: Database Constraint + Application Guard
@Entity
@Table(
name = "reservations",
uniqueConstraints = [
UniqueConstraint(columnNames = ["variant_id", "order_id"])
]
)
class Reservation(
@Column(name = "variant_id", nullable = false)
val variantId: Long,
@Column(name = "order_id", nullable = false)
val orderId: String,
@Column(nullable = false)
var quantity: Int
) {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long = 0
}
interface ReservationRepository : JpaRepository<Reservation, Long> {
fun findByVariantIdAndOrderId(variantId: Long, orderId: String): Reservation?
}
@Service
class ReservationService(private val repo: ReservationRepository) {
@Transactional
fun createReservation(variantId: Long, orderId: String, qty: Int): Reservation {
repo.findByVariantIdAndOrderId(variantId, orderId)?.let {
throw IllegalStateException(
"Reservation already exists for variant=$variantId, order=$orderId"
)
}
return repo.save(Reservation(variantId = variantId, orderId = orderId, quantity = qty))
}
}Key rules:
- Database constraint is mandatory — application checks alone have race conditions
- Application check provides clean error messages — without it, users get raw
DataIntegrityViolationException - Both layers together: application catches the common case, database catches the race
- Spring Data derives
findByXAndYqueries automatically
Query and Fetch Rules
- Diagnose N+1 by looking at actual query count or SQL logs, not by guessing from annotations.
- Prefer targeted fetch solutions:
@EntityGraph,JOIN FETCH, batch fetching, or DTO projection. - Be careful with collection fetch joins plus pagination — call out the tradeoff.
- Use indexes and uniqueness constraints to support real query patterns.
Common ORM Traps
- Bidirectional associations: maintain both sides in domain methods. Half-updated graphs cause subtle bugs.
orphanRemovalvs cascade remove: not interchangeable. Explain lifecycle semantics before choosing.- Lazy load triggers:
toString, debug logging, JSON serialization, and IDE inspection can all trigger lazy loads. - Bulk updates/deletes: bypass persistence context and lifecycle callbacks. Subsequent reads may be stale.
- Multiple bag fetches: can cause Cartesian explosion. Verify the ORM can execute collection-heavy fetch plans safely.
Set+ mutable equality: collection membership can break after entity state changes.@Version: the clearest optimistic concurrency mechanism when concurrent updates matter.open-in-viewdisabled: DTO mapping touching lazy fields must happen inside a transaction boundary.
Guardrails
- Do not use
data classfor JPA entities. - Do not recommend
FetchType.EAGEReverywhere to silence lazy loading symptoms. - Do not expose entities directly through API responses by default.
- Do not claim an N+1 fix without explaining how the fetch plan changes query behavior.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

