Last active
November 16, 2023 02:35
-
-
Save FrancescoJo/ca72628ee7be42b6f49d2f6b90dbfa26 to your computer and use it in GitHub Desktop.
Hibernate error while upgrading Spring boot 2.7 to 3.0(Hibernate 5.x to 6.1)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// UserEntity.kt | |
@Entity | |
@Table(name = "users") | |
class UserEntity( | |
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) | |
@Column(name = "id") | |
val id: Long = 0L, | |
@Column(name = "isDeleted") | |
var isDeleted: Boolean = false, | |
@Version | |
@Column(name = "version") | |
override var version: Long = Versioned.DEFAULT_LONG_INT | |
) | |
// BuyerEntity.kt | |
// Since Hibernate 6 we have to make BuyerEntity extend UserEntity to find businessInformation properly. | |
@Entity | |
@Table(name = "users_buyers") | |
class BuyerEntity( | |
@Id | |
@Column(name = "users_id") | |
val id: Long = 0L, | |
user: UserEntity, | |
/* | |
* This configuration was fine in Hibernate 5, but in version 6 it causes application startup failure by raising a Runtime exception as follows: | |
* | |
* org.hibernate.AnnotationException: Association 'BuyerEntity.businessInformation' is 'mappedBy' a property named 'ownerUser' which references the wrong entity type 'UserEntity', expected 'BuyerEntity' | |
*/ | |
@OneToMany( | |
fetch = FetchType.LAZY, | |
mappedBy = "ownerUser", | |
cascade = [CascadeType.ALL], | |
orphanRemoval = true | |
) | |
var businessInformation: MutableSet<BuyerBusinessInfoEntity> = mutableSetOf(), | |
) | |
// AbstractBusinessInfoEntityTemplate.kt | |
@Inheritance // Caution: We can't code this as Kotlin sealed class since Hibernate could not makes proxy object properly. | |
@Entity | |
@Table(name = "business_info") | |
@DiscriminatorColumn(name = "business_type_code") | |
abstract class AbstractBusinessInfoEntityTemplate { | |
@get:jakarta.persistence.Transient | |
abstract val type: AbstractBusinessInfoEntityTemplate.Type | |
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) | |
@Column(name = "id") | |
val id: Long = 0L | |
// To refer this field in BuyerEntity the type of this field should be BuyerEntity but it is impossible since both types are incompatible at the moment | |
@ManyToOne(fetch = FetchType.LAZY) | |
@JoinColumn(name = "users_id") | |
var ownerUser: UserEntity? = null | |
@Column(name = "licence_number") | |
var licenceNumber: String = "" | |
@Column(name = "name") | |
var name: String = "" | |
enum class Type { | |
BUYER, | |
USER | |
} | |
} | |
// BuyerBusinessInfoEntity.kt | |
@Entity | |
@DiscriminatorValue(DISCRIMINATOR_VALUE) | |
class BuyerBusinessInfoEntity : AbstractBusinessInfoEntityTemplate() { | |
@Transient | |
override val type: AbstractBusinessInfoEntityTemplate.Type = AbstractBusinessInfoEntityTemplate.Type.BUYER | |
companion object { | |
const val DISCRIMINATOR_VALUE = "b" | |
} | |
} | |
/* | |
Full exception stack trace: | |
Caused by: org.hibernate.AnnotationException: Association 'BuyerEntity.businessInformation' is 'mappedBy' a property named 'ownerUser' which references the wrong entity type 'UserEntity', expected 'BuyerEntity' | |
at app//org.hibernate.boot.model.internal.BinderHelper.checkMappedByType(BinderHelper.java:1104) | |
at app//org.hibernate.boot.model.internal.CollectionBinder.isReversePropertyInJoin(CollectionBinder.java:1572) | |
at app//org.hibernate.boot.model.internal.CollectionBinder.noAssociationTable(CollectionBinder.java:1583) | |
at app//org.hibernate.boot.model.internal.CollectionBinder.bindStarToManySecondPass(CollectionBinder.java:1544) | |
at app//org.hibernate.boot.model.internal.CollectionBinder$1.secondPass(CollectionBinder.java:1535) | |
at app//org.hibernate.boot.model.internal.CollectionSecondPass.doSecondPass(CollectionSecondPass.java:45) | |
at app//org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1870) | |
at app//org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1826) | |
at app//org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:331) | |
at app//org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:1380) | |
at app//org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1451) | |
at app//org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:75) | |
at app//org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:376) | |
at app//org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:409) | |
at app//org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:396) | |
at app//org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet(LocalContainerEntityManagerFactoryBean.java:352) | |
at app//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1817) | |
at app//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1766) | |
*/ | |
// Table structure | |
CREATE TABLE IF NOT EXISTS `users` | |
( | |
`id` BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, | |
`isDeleted` BOOLEAN DEFAULT FALSE, | |
`version` BIGINT NOT NULL | |
); | |
CREATE TABLE IF NOT EXISTS `buyers` | |
( | |
`users_id` BIGINT PRIMARY KEY REFERENCES `users` (`id`) | |
); | |
CREATE TABLE IF NOT EXISTS `business_info` | |
( | |
`id` BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, | |
`users_id` BIGINT NULL, | |
`licence_number` VARCHAR(24) DEFAULT NULL, | |
`name` VARCHAR(64) DEFAULT NULL | |
`business_type_code` VARCHAR(4) NOT NULL, | |
INDEX `idx_business_info_identity` (`licence_number`, `name`, `business_type_code`), | |
CONSTRAINT `fk_business_info_user_id` FOREIGN KEY (`users_id`) REFERENCES `users` (`id`) | |
); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment