2016-06-09 19 views
5

La maggior parte Kotlin JPA codice di esempio si presentaKotlin con JPA/Hibernate: nessun caricamento pigro senza `open`?

class Person(val name: String, val age: Int) { /* ... */ } 

o anche

data class Person(val name: String="", val age: Int=0) { /* ... */ } 

Ora, il Hibernate User Guide, e credo che anche molti altri ORM, statali che di solito vogliono creare proxy o comunque estendere la classe del modello, ma per consentire che in Kotlin la classe debba essere definita esplicitamente open. Questo è attualmente impossibile con le classi di dati e presumo, a giudicare dalla mia esperienza, che molte persone non ci pensano quando scrivono entità JPA in Kotlin.

Quindi, per venire alla mia domanda (questo è StackOverflow dopo tutto), è sufficiente fare

open class Person(val name: String, val age: Int) { /* ... */ } 

o sarebbe in realtà hanno a che fare

open class Person(open val name: String, open val age: Int) { /* ... */ } 

di non inutilmente ostacolare il ORM a fare il suo lavoro correttamente?
Se è davvero dannoso, dovremmo probabilmente proporre di aggiungere un avviso a IntelliJ IDEA, che se una classe ha un'annotazione @Entity, dovrebbe essere definita open.

+0

Non vedo come la parola "nocivo" sia applicabile qui. Potresti chiarire il suo uso o cancellarlo dalla domanda se non è importante? – voddan

+0

Principalmente è il fatto che almeno Hibernate non può eseguire il caricamento lazy di classi definitive o con metodi di accesso definitivi e l'utilizzo di classi di dati per JPA spesso sembra una buona cosa da fare, ma può davvero danneggiare le prestazioni, perché sono definitive per definizione (almeno al momento, sentito che può cambiare). Il titolo è molto cliccabile, perché pensavo che dovesse essere qualcosa di più universalmente noto e per evitare ad es. le applicazioni trasferite su Kotlin hanno prestazioni peggiori rispetto alla controparte Java e gli utenti accusano Kotlin:/ – johnp

+0

Grazie per aver parafrasato la domanda! – voddan

risposta

6

Il tutorial che hai fornito specifica:

La classe entità deve avere un pubblico o protetto non-argomento del costruttore ... interfaccia non può essere designato come entità ... La classe di entità non deve essere definitiva . Nessun metodo o variabile di istanza persistente della classe entità può essere finale.

Le classi di Kotlin seguono la convenzione JavaBeans per setter/getter.

Se l'ORM ha requisiti di cui sopra, allora si hanno infatti specificare open sulla classe ei suoi metodi:

open class Person(open val name: String = "", 
        open val age: Int = 0) 

I valori di default per tutti i parametri del costruttore consentono Kotlin per generare un ulteriore vuoto costruttore. In alternativa è possibile fornire come un costruttore secondaria:

open class Person(open val name: String, open val age: Int) { 
    constructor() : this("", 0) 
} 

Nota che open val crea un campo finale privato e un getter aperta. Se ciò non è sufficiente, utilizza annotazioni come @JvmField open val name.

Gli ORM come quelli in uso hanno un attrito aggiuntivo con il codice Kotlin a causa degli schemi di progettazione discutibili che usano (come rendere tutto non-finale).

Una buona opzione è utilizzare un ORM specifico di Kotlin. Ad esempio, Exposed è supportato da JetBrains e utilizzato per alcuni dei suoi prodotti, che parla da solo. Un'altra opzione è Ebean che supporta ufficialmente Kotlin (grazie a @johnp)

+1

Grazie per la risposta! Una delle cose che mi sembrava strana era che le classi finali non potevano essere caricate in Hibernate e immaginavo che avrebbe potuto seriamente danneggiare le prestazioni se non fosse stato preso in considerazione. Personalmente sono passato a [Ebean] (https://ebean-orm.github.io/) un paio di settimane fa, perché menziona esplicitamente Kotlin e ha una barriera di ingresso inferiore a quella di Hibernate, ma non ho ancora sentito parlare di Exposed e sicuramente dare un'occhiata a questo. – johnp

+0

Caricamento lento significa che Hibernate deve caricare i dati solo quando il getter viene richiamato per la prima volta. Tuttavia, il getter è già implementato da un programmatore (come un semplice campo letto)! Hibernate deve quindi modificare la funzionalità di quel metodo in modo che esegua il polling del JDBC al momento della chiamata. È possibile modificare un metodo modificando il bytecode in fase di compilazione o estendendo dinamicamente la classe e sovrascrivendo i setter. –

+0

Se si è disposti a considerare un ORM specifico di Kotlin, https://github.com/mvysny/vok-orm potrebbe essere una buona opzione. Usa ancora POJO che potrebbero ad es. essere annotato con annotazioni JSR303 e passato ai moduli web; usa Sql2o dietro le quinte; si concentra su Kotlin come unica lingua obiettivo. Disclaimer: io sono l'autore. –

Problemi correlati