Arbeiten mit Kotlin und JPA
1. Einführung
Eine der Eigenschaften von Kotlin sind dieinteroperability with Java-Bibliotheken, und JPA ist sicherlich eine davon.
In diesem Tutorial erfahren Sie, wie SieKotlin Data Classesals JPA-Entitäten verwenden.
2. Abhängigkeiten
Zur Vereinfachung verwenden wir Hibernate als JPA-Implementierung. Wir müssen unserem Maven-Projekt die folgenden Abhängigkeiten hinzufügen:
org.hibernate
hibernate-core
5.2.15.Final
org.hibernate
hibernate-testing
5.2.15.Final
test
Wir werden auch eine eingebettete H2-Datenbank verwenden, um unsere Tests auszuführen:
com.h2database
h2
1.4.196
test
Für Kotlin verwenden wir Folgendes:
org.jetbrains.kotlin
kotlin-stdlib-jdk8
1.2.30
3. Compiler Plugins (jpa-Plugin)
Zur Verwendung von JPA benötigen die Entitätsklassen einen Konstruktor ohne Parameter.
Standardmäßig verfügen die Kotlin-Datenklassen nicht darüber. Um sie zu generieren, müssen Sie diejpa-plugin verwenden:
kotlin-maven-plugin
org.jetbrains.kotlin
1.2.30
jpa
1.8
org.jetbrains.kotlin
kotlin-maven-noarg
1.2.30
4. JPA mit Kotlin-Datenklassen
Nachdem das vorherige Setup abgeschlossen ist, können wir JPA mit Datenklassen verwenden.
Beginnen wir mit der Erstellung einerPerson-Datenklasse mit zwei Attributen -id undname wie folgt:
@Entity
data class Person(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Int,
@Column(nullable = false)
val name: String
)
Wie wir sehen können, können wir die Annotationen von JPA wie@Entity, @Column und@Id frei verwenden.
Um unsere Entität in Aktion zu sehen, erstellen wir den folgenden Test:
@Test
fun givenPerson_whenSaved_thenFound() {
doInHibernate(({ this.sessionFactory() }), { session ->
val personToSave = Person(0, "John")
session.persist(personToSave)
val personFound = session.find(Person::class.java, personToSave.id)
session.refresh(personFound)
assertTrue(personToSave == personFound)
})
}
Nachdem der Test mit aktivierter Protokollierung ausgeführt wurde, werden die folgenden Ergebnisse angezeigt:
Hibernate: insert into Person (id, name) values (null, ?)
Hibernate: select person0_.id as id1_0_0_, person0_.name as name2_0_0_ from Person person0_ where person0_.id=?
Das ist ein Indikator dafür, dass alles gut läuft. Es ist wichtig zu beachten, dassif we don’t use the jpa-plugin in runtime, we are going to get an InstantiationException, due to the lack of default constructor:
javax.persistence.PersistenceException: org.hibernate.InstantiationException: No default constructor for entity: : com.example.entity.Person
Jetzt werden wir erneut mitnull Werten testen. Erweitern wir dazu die EntitätPersonum ein neues Attributemail und eine Beziehung@OneToMany:
//...
@Column(nullable = true)
val email: String? = null,
@Column(nullable = true)
@OneToMany(cascade = [CascadeType.ALL])
val phoneNumbers: List? = null
Wir können auch sehen, dass die Felderemail undphoneNumbers nullwertfähig sind und daher mit dem Fragezeichen deklariert werden.
Die EntitätPhoneNumberhat zwei Attribute -id undnumber:
@Entity
data class PhoneNumber(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Int,
@Column(nullable = false)
val number: String
)
Lassen Sie uns dies mit einem Test überprüfen:
@Test
fun givenPersonWithNullFields_whenSaved_thenFound() {
doInHibernate(({ this.sessionFactory() }), { session ->
val personToSave = Person(0, "John", null, null)
session.persist(personToSave)
val personFound = session.find(Person::class.java, personToSave.id)
session.refresh(personFound)
assertTrue(personToSave == personFound)
})
}
Dieses Mal erhalten wir eine Einfügeanweisung:
Hibernate: insert into Person (id, email, name) values (null, ?, ?)
Hibernate: select person0_.id as id1_0_1_, person0_.email as email2_0_1_, person0_.name as name3_0_1_, phonenumbe1_.Person_id as Person_i1_1_3_, phonenumbe2_.id as phoneNum2_1_3_, phonenumbe2_.id as id1_2_0_, phonenumbe2_.number as number2_2_0_ from Person person0_ left outer join Person_PhoneNumber phonenumbe1_ on person0_.id=phonenumbe1_.Person_id left outer join PhoneNumber phonenumbe2_ on phonenumbe1_.phoneNumbers_id=phonenumbe2_.id where person0_.id=?
Lassen Sie uns noch einmal testen, jedoch ohnenull Daten, um die Ausgabe zu überprüfen:
@Test
fun givenPersonWithFullData_whenSaved_thenFound() {
doInHibernate(({ this.sessionFactory() }), { session ->
val personToSave = Person(
0,
"John",
"[email protected]",
Arrays.asList(PhoneNumber(0, "202-555-0171"), PhoneNumber(0, "202-555-0102")))
session.persist(personToSave)
val personFound = session.find(Person::class.java, personToSave.id)
session.refresh(personFound)
assertTrue(personToSave == personFound)
})
}
Und wie wir sehen können, erhalten wir jetzt drei insert-Anweisungen:
Hibernate: insert into Person (id, email, name) values (null, ?, ?)
Hibernate: insert into PhoneNumber (id, number) values (null, ?)
Hibernate: insert into PhoneNumber (id, number) values (null, ?)
5. Fazit
In diesem kurzen Artikel haben wir ein Beispiel für die Integration von Kotlin-Datenklassen in JPA mithilfe des JPA-Plugins und von Hibernate gesehen.
Wie immer ist der Quellcodeover on GitHub. verfügbar