Skip to content

Commit 49b72df

Browse files
committed
Hibernate example: add JPA plugin, use built-in transaction handling, other improvements
1 parent 0263510 commit 49b72df

8 files changed

Lines changed: 60 additions & 104 deletions

File tree

examples/projects/dev/hibernate/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
plugins {
22
alias(libs.plugins.kotlin.jvm)
33
alias(libs.plugins.kotlin.dataframe)
4+
alias(libs.plugins.kotlin.jpa)
45
alias(libs.plugins.ktlint.gradle)
56

67
application

examples/projects/dev/hibernate/gradle/libs.versions.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,5 @@ ktlint-gradle = { id = "org.jlleitschuh.gradle.ktlint", version.ref = "ktlint-gr
2222

2323
# The Kotlin DataFrame Compiler plugin is the same version as the Kotlin plugin.
2424
kotlin-dataframe = { id = "org.jetbrains.kotlin.plugin.dataframe", version.ref = "kotlin" }
25+
26+
kotlin-jpa = { id = "org.jetbrains.kotlin.plugin.jpa", version.ref = "kotlin" }

examples/projects/dev/hibernate/src/main/kotlin/org/jetbrains/kotlinx/dataframe/examples/hibernate/entities.kt

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@ package org.jetbrains.kotlinx.dataframe.examples.hibernate
22

33
import jakarta.persistence.Column
44
import jakarta.persistence.Entity
5+
import jakarta.persistence.FetchType
56
import jakarta.persistence.GeneratedValue
67
import jakarta.persistence.GenerationType
78
import jakarta.persistence.Id
9+
import jakarta.persistence.JoinColumn
10+
import jakarta.persistence.ManyToOne
811
import jakarta.persistence.Table
912
import org.jetbrains.kotlinx.dataframe.annotations.ColumnName
1013
import org.jetbrains.kotlinx.dataframe.annotations.DataSchema
@@ -17,9 +20,10 @@ class AlbumsEntity(
1720
@Column(name = "AlbumId")
1821
var albumId: Int? = null,
1922
@Column(name = "Title", length = 160, nullable = false)
20-
var title: String = "",
21-
@Column(name = "ArtistId", nullable = false)
22-
var artistId: Int = 0,
23+
var title: String,
24+
@ManyToOne(fetch = FetchType.LAZY, optional = false)
25+
@JoinColumn(name = "ArtistId", nullable = false)
26+
var artist: ArtistsEntity,
2327
)
2428

2529
@Entity
@@ -30,7 +34,7 @@ class ArtistsEntity(
3034
@Column(name = "ArtistId")
3135
var artistId: Int? = null,
3236
@Column(name = "Name", length = 120, nullable = false)
33-
var name: String = "",
37+
var name: String,
3438
)
3539

3640
@Entity
@@ -41,9 +45,9 @@ class CustomersEntity(
4145
@Column(name = "CustomerId")
4246
var customerId: Int? = null,
4347
@Column(name = "FirstName", length = 40, nullable = false)
44-
var firstName: String = "",
48+
var firstName: String,
4549
@Column(name = "LastName", length = 20, nullable = false)
46-
var lastName: String = "",
50+
var lastName: String,
4751
@Column(name = "Company", length = 80)
4852
var company: String? = null,
4953
@Column(name = "Address", length = 70)
@@ -61,7 +65,7 @@ class CustomersEntity(
6165
@Column(name = "Fax", length = 24)
6266
var fax: String? = null,
6367
@Column(name = "Email", length = 60, nullable = false)
64-
var email: String = "",
68+
var email: String,
6569
@Column(name = "SupportRepId")
6670
var supportRepId: Int? = null,
6771
)

examples/projects/dev/hibernate/src/main/kotlin/org/jetbrains/kotlinx/dataframe/examples/hibernate/main.kt

Lines changed: 16 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import jakarta.persistence.criteria.CriteriaDelete
55
import jakarta.persistence.criteria.CriteriaQuery
66
import jakarta.persistence.criteria.Root
77
import org.hibernate.FlushMode
8+
import org.hibernate.Session
89
import org.hibernate.SessionFactory
910
import org.hibernate.hikaricp.internal.HikariCPConnectionProvider
1011
import org.hibernate.jpa.HibernatePersistenceConfiguration
@@ -45,17 +46,16 @@ fun main() {
4546
}
4647

4748
private fun SessionFactory.insertSampleData() {
48-
withTransaction { session ->
49+
inTransaction { session ->
4950
// a few artists and albums (minimal, not used further; just demo schema)
5051
val artist1 = ArtistsEntity(name = "AC/DC")
5152
val artist2 = ArtistsEntity(name = "Queen")
5253
session.persist(artist1)
5354
session.persist(artist2)
54-
session.flush()
5555

56-
session.persist(AlbumsEntity(title = "High Voltage", artistId = artist1.artistId!!))
57-
session.persist(AlbumsEntity(title = "Back in Black", artistId = artist1.artistId!!))
58-
session.persist(AlbumsEntity(title = "A Night at the Opera", artistId = artist2.artistId!!))
56+
session.persist(AlbumsEntity(title = "High Voltage", artist = artist1))
57+
session.persist(AlbumsEntity(title = "Back in Black", artist = artist1))
58+
session.persist(AlbumsEntity(title = "A Night at the Opera", artist = artist2))
5959
// customers we'll analyze using DataFrame
6060
session.persist(
6161
CustomersEntity(
@@ -91,15 +91,15 @@ private fun SessionFactory.loadCustomersAsDataFrame(): DataFrame<DfCustomers> =
9191
val root: Root<CustomersEntity> = criteriaQuery.from(CustomersEntity::class.java)
9292
criteriaQuery.select(root)
9393

94-
session.createQuery(criteriaQuery)
94+
session.createSelectionQuery(criteriaQuery)
9595
.resultList
9696
.map { c ->
9797
DfCustomers(
9898
address = c.address,
9999
city = c.city,
100100
company = c.company,
101101
country = c.country,
102-
customerId = c.customerId ?: -1,
102+
customerId = c.customerId ?: error("Loaded customer must have a generated id"),
103103
email = c.email,
104104
fax = c.fax,
105105
firstName = c.firstName,
@@ -120,7 +120,7 @@ private fun SessionFactory.loadCustomersAsDataFrame(): DataFrame<DfCustomers> =
120120
}
121121

122122
/** DTO used for aggregation projection. */
123-
private data class CountryCountDto(val country: String, val customerCount: Long)
123+
private data class CountryCountDto(val country: String?, val customerCount: Long)
124124

125125
/**
126126
* **Hibernate + Criteria API:**
@@ -134,9 +134,8 @@ private fun SessionFactory.countCustomersPerCountryWithHibernate() {
134134
val cb = session.criteriaBuilder
135135
val cq: CriteriaQuery<CountryCountDto> = cb.createQuery(CountryCountDto::class.java)
136136
val root: Root<CustomersEntity> = cq.from(CustomersEntity::class.java)
137-
138-
val countryPath = root.get<String>("country")
139-
val idPath = root.get<Long>("customerId")
137+
val countryPath = root.get<String?>("country")
138+
val idPath = root.get<Int?>("customerId")
140139

141140
val countExpr = cb.count(idPath)
142141

@@ -150,7 +149,7 @@ private fun SessionFactory.countCustomersPerCountryWithHibernate() {
150149
cq.groupBy(countryPath)
151150
cq.orderBy(cb.desc(countExpr))
152151

153-
val results = session.createQuery(cq).resultList
152+
val results = session.createSelectionQuery(cq).resultList
154153
results.forEach { dto ->
155154
println("${dto.country}: ${dto.customerCount} customers")
156155
}
@@ -177,22 +176,18 @@ private fun DataFrame<DfCustomers>.analyzeAndPrintResults() {
177176
.print(columnTypes = true, borders = true)
178177
}
179178

180-
private fun SessionFactory.replaceCustomersFromDataFrame(df: DataFrame<DfCustomers>) {
181-
withTransaction { session ->
179+
private fun SessionFactory.replaceCustomersFromDataFrame(df: DataFrame<DfCustomers>) =
180+
inTransaction { session ->
182181
val criteriaBuilder: CriteriaBuilder = session.criteriaBuilder
183182
val criteriaDelete: CriteriaDelete<CustomersEntity> =
184183
criteriaBuilder.createCriteriaDelete(CustomersEntity::class.java)
185184
criteriaDelete.from(CustomersEntity::class.java)
186-
187185
session.createMutationQuery(criteriaDelete).executeUpdate()
188-
}
189186

190-
withTransaction { session ->
191187
df.asSequence().forEach { row ->
192188
session.persist(row.toCustomersEntity())
193189
}
194190
}
195-
}
196191

197192
private fun DataRow<DfCustomers>.toCustomersEntity(): CustomersEntity =
198193
CustomersEntity(
@@ -211,37 +206,13 @@ private fun DataRow<DfCustomers>.toCustomersEntity(): CustomersEntity =
211206
supportRepId = this.supportRepId,
212207
)
213208

214-
private inline fun <T> SessionFactory.withSession(block: (session: org.hibernate.Session) -> T): T =
215-
openSession().use(block)
216-
217-
private inline fun SessionFactory.withTransaction(block: (session: org.hibernate.Session) -> Unit) {
218-
withSession { session ->
219-
session.beginTransaction()
220-
try {
221-
block(session)
222-
session.transaction.commit()
223-
} catch (e: Exception) {
224-
session.transaction.rollback()
225-
throw e
226-
}
227-
}
228-
}
229-
230209
/** Read-only transaction helper for SELECT queries to minimize overhead. */
231-
private inline fun <T> SessionFactory.withReadOnlyTransaction(block: (session: org.hibernate.Session) -> T): T =
232-
withSession { session ->
233-
session.beginTransaction()
210+
private inline fun <T> SessionFactory.withReadOnlyTransaction(crossinline block: (session: Session) -> T): T =
211+
fromTransaction { session ->
234212
// Minimize overhead for read operations
235213
session.isDefaultReadOnly = true
236214
session.hibernateFlushMode = FlushMode.MANUAL
237-
try {
238-
val result = block(session)
239-
session.transaction.commit()
240-
result
241-
} catch (e: Exception) {
242-
session.transaction.rollback()
243-
throw e
244-
}
215+
block(session)
245216
}
246217

247218
private fun buildSessionFactory(): SessionFactory =

examples/projects/hibernate/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
plugins {
22
alias(libs.plugins.kotlin.jvm)
33
alias(libs.plugins.kotlin.dataframe)
4+
alias(libs.plugins.kotlin.jpa)
45
alias(libs.plugins.ktlint.gradle)
56

67
application

examples/projects/hibernate/gradle/libs.versions.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,5 @@ ktlint-gradle = { id = "org.jlleitschuh.gradle.ktlint", version.ref = "ktlint-gr
2222

2323
# The Kotlin DataFrame Compiler plugin is the same version as the Kotlin plugin.
2424
kotlin-dataframe = { id = "org.jetbrains.kotlin.plugin.dataframe", version.ref = "kotlin" }
25+
26+
kotlin-jpa = { id = "org.jetbrains.kotlin.plugin.jpa", version.ref = "kotlin" }

examples/projects/hibernate/src/main/kotlin/org/jetbrains/kotlinx/dataframe/examples/hibernate/entities.kt

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@ package org.jetbrains.kotlinx.dataframe.examples.hibernate
22

33
import jakarta.persistence.Column
44
import jakarta.persistence.Entity
5+
import jakarta.persistence.FetchType
56
import jakarta.persistence.GeneratedValue
67
import jakarta.persistence.GenerationType
78
import jakarta.persistence.Id
9+
import jakarta.persistence.JoinColumn
10+
import jakarta.persistence.ManyToOne
811
import jakarta.persistence.Table
912
import org.jetbrains.kotlinx.dataframe.annotations.ColumnName
1013
import org.jetbrains.kotlinx.dataframe.annotations.DataSchema
@@ -17,9 +20,10 @@ class AlbumsEntity(
1720
@Column(name = "AlbumId")
1821
var albumId: Int? = null,
1922
@Column(name = "Title", length = 160, nullable = false)
20-
var title: String = "",
21-
@Column(name = "ArtistId", nullable = false)
22-
var artistId: Int = 0,
23+
var title: String,
24+
@ManyToOne(fetch = FetchType.LAZY, optional = false)
25+
@JoinColumn(name = "ArtistId", nullable = false)
26+
var artist: ArtistsEntity,
2327
)
2428

2529
@Entity
@@ -30,7 +34,7 @@ class ArtistsEntity(
3034
@Column(name = "ArtistId")
3135
var artistId: Int? = null,
3236
@Column(name = "Name", length = 120, nullable = false)
33-
var name: String = "",
37+
var name: String,
3438
)
3539

3640
@Entity
@@ -41,9 +45,9 @@ class CustomersEntity(
4145
@Column(name = "CustomerId")
4246
var customerId: Int? = null,
4347
@Column(name = "FirstName", length = 40, nullable = false)
44-
var firstName: String = "",
48+
var firstName: String,
4549
@Column(name = "LastName", length = 20, nullable = false)
46-
var lastName: String = "",
50+
var lastName: String,
4751
@Column(name = "Company", length = 80)
4852
var company: String? = null,
4953
@Column(name = "Address", length = 70)
@@ -61,7 +65,7 @@ class CustomersEntity(
6165
@Column(name = "Fax", length = 24)
6266
var fax: String? = null,
6367
@Column(name = "Email", length = 60, nullable = false)
64-
var email: String = "",
68+
var email: String,
6569
@Column(name = "SupportRepId")
6670
var supportRepId: Int? = null,
6771
)

0 commit comments

Comments
 (0)