在Kotlin中通过JPA注解实现从基类继承实体属性
Great question! Creating a base entity class is exactly the right move to cut down on repetitive boilerplate (like @Id, @UpdateTimestamp, and optimistic locking) across your team's JPA entities. Here's a step-by-step guide to make this work smoothly:
1. Finalize Your Base Entity with @MappedSuperclass
First, refine your JpaEntity base class using JPA's @MappedSuperclass annotation. This tells JPA that the class's attributes should be inherited by child entities, but the base class itself won't be mapped to a database table. We'll also add the optimistic lock field with @Version since you mentioned it:
import jakarta.persistence.* import java.time.LocalDateTime @MappedSuperclass open class JpaEntity( @Id @GeneratedValue(strategy = GenerationType.IDENTITY) var id: Long? = null, @UpdateTimestamp @Column(nullable = false) var lastUpdate: LocalDateTime? = null, @Version @Column(nullable = false) var version: Long = 0L )
Key Details:
@MappedSuperclass: Critical for ensuring JPA recognizes this as a parent class whose fields are inherited by entities.openmodifier (Kotlin-specific): Required because Kotlin classes arefinalby default—child entities need to extend this class.@Version: Enables JPA's optimistic locking, which prevents concurrent modification issues automatically.@Column(nullable = false): Ensures these core fields can't be null in the database, adding data integrity.
2. Extend the Base Class in Your Entities
Now all your team's entities can simply extend JpaEntity instead of redefining the common fields. Here's an example:
import jakarta.persistence.Entity @Entity class Product( // Only define entity-specific fields here var name: String, var price: Double ) : JpaEntity()
That's it! The Product entity automatically gets id, lastUpdate, and version fields without any extra code.
3. Enforce Team Adoption & Add Optional Enhancements
To make sure your team follows this practice and gets the most out of the base class:
- Document the rule: Add a note in your project's style guide that all JPA entities must extend
JpaEntity. - Code reviews: Include a check for this during peer reviews to catch any entities that don't follow the pattern.
- Static analysis: Use tools like SonarQube to enforce that all
@Entityclasses extend your base class. - Expand the base class: Add other common fields your team uses, like a
@CreatedTimestampfor creation time or aisDeletedflag for soft deletion:@CreatedTimestamp @Column(nullable = false) var createTime: LocalDateTime? = null, var isDeleted: Boolean = false
Alternative Approach (If Inheritance Isn't Preferred)
If your team is hesitant about class inheritance, you could use JPA's attribute converters or annotation processors, but these are more complex. The @MappedSuperclass approach is by far the most straightforward, readable, and maintainable solution for this use case.
By centralizing these common fields, you'll reduce bugs from inconsistent implementations, save time on repetitive code, and keep your entity classes focused on their specific business logic.
内容的提问来源于stack exchange,提问作者Stijn Vanpoucke

