2016-06-09 7 views
5

meisten Kotlin JPA Beispiel-Code sieht wie folgt ausKotlin mit JPA/Hibernate: kein Lazy-Loading ohne `open`?

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

oder sogar

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

nun die Hibernate User Guide, und ich denke, auch mehrere andere ORMs an, daß sie wollen in der Regel Proxies erstellen oder auf andere Weise erweitern die Modellklasse, aber um dies in Kotlin zu ermöglichen, muss die Klasse explizit definiert werden open. Dies ist derzeit bei Datenklassen nicht möglich, und ich gehe davon aus, dass die meisten Leute bei der Erstellung von JPA-Entitäten in Kotlin nicht darüber nachdenken.

, also auf meine Frage kommen (das ist Stackoverflow, nachdem alle), ist es genug

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

oder würden wir tun müssen, tatsächlich

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

nicht unnötig zu behindern, tun ORM bei seiner Arbeit richtig machen?
Wenn es wirklich schädlich ist, sollten wir wahrscheinlich vorschlagen, IntelliJ IDEA eine Warnung hinzuzufügen, dass, wenn eine Klasse eine @Entity Annotation hat, sollte sie open definiert werden.

+0

Ich sehe nicht, wie das Wort "schädlich" hier anwendbar ist. Können Sie seine Verwendung klären oder aus der Frage löschen, wenn es nicht wichtig ist? – voddan

+0

Hauptsächlich ist es die Tatsache, dass zumindest Hibernate keine Lazy-Loads für finale oder finale Accessor-Methoden ausführen kann und die Verwendung von Datenklassen für JPA sieht oft gut aus, kann aber die Performance beeinträchtigen, da sie per Definition final sind (zumindest im Moment, hörte, dass sich das ändern kann). Der Titel ist sehr Clickbaity, weil ich dachte, dass etwas allgemein bekannter sein sollte und z. Anwendungen, die nach Kotlin portiert wurden, haben eine schlechtere Leistung als das Java-Pendant und die Benutzer beschuldigen Kotlin:/ – johnp

+0

Vielen Dank, dass Sie die Frage paraphrasiert haben! – voddan

Antwort

6

Das Tutorial Sie gibt an zur Verfügung gestellt:

Die Entity-Klasse muss eine öffentliche oder Konstruktor ohne Argumente geschützt ... Schnittstelle nicht als Einheit bezeichnet werden kann ... Die Entity-Klasse darf nicht endgültig . Keine Methoden oder persistenten Instanzvariablen der Entitätsklasse können endgültig sein.

Kotlin-Klassen folgen der JavaBeans-Konvention für Setter/Getter.

Wenn Ihre ORM Anforderungen wie oben hat, dann haben Sie in der Tat open auf die Klasse und ihre Methoden zu spezifizieren:

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

Die Standardwerte für alle der Konstruktor Parameter erlauben Kotlin eine zusätzliche leer zu erzeugen Konstrukteur. Alternativ können Sie es als sekundären Konstruktor bieten:

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

Beachten Sie, dass open val ein eigenes letztes Feld erzeugt und ein offenes Getter. Wenn das nicht genug ist, verwenden Sie Annotationen wie @JvmField open val name.

ORMs wie die, die Sie verwenden, haben zusätzliche Reibung mit Kotlin-Code wegen der fragwürdigen Design-Muster, die sie verwenden (wie alles nicht final).

Eine gute Option ist die Verwendung eines Kotlin-spezifischen ORM. Zum Beispiel wird Exposed von JetBrains unterstützt und für einige seiner Produkte verwendet, was für sich spricht. Eine andere Option ist Ebean, die Kotlin offiziell unterstützt (danke @johnp)

+1

Vielen Dank für Ihre Antwort! Eine der Sachen, die mir auffiel, war, dass die letzten Klassen in Hibernate nicht faul geladen werden konnten und ich dachte mir, dass dies die Performance ernsthaft beeinträchtigen könnte, wenn man sie nicht in Betracht zieht. Ich persönlich bin vor ein paar Wochen zu [Ebbean] (https://ebean-orm.github.io/) gewechselt, weil es Kotlin ausdrücklich erwähnt und eine niedrigere Einstiegsbarriere als Hibernate hat, aber ich habe noch nicht von Exposed gehört und werde es mir auf jeden Fall anschauen. – johnp

+0

Lazy Loading bedeutet, dass Hibernate die Daten nur laden muss, wenn der Getter zum ersten Mal aufgerufen wird. Der Getter wird jedoch bereits von einem Programmierer implementiert (als einfaches Feldlesen)! Hibernate muss daher die Funktionalität dieser Methode ändern, sodass sie die JDBC zum Zeitpunkt des Anrufs abfragt. Sie können eine Methode ändern, indem Sie den Bytecode bei der Kompilierungsphase ändern oder indem Sie die Klasse dynamisch erweitern und die Setter überschreiben. –

+0

Wenn Sie bereit sind, ein Kotlin-spezifisches ORM in Betracht zu ziehen, könnte https://github.com/mvysny/vok-orm eine gute Option sein. Es verwendet immer noch POJOs, die z.B. mit JSR303-Annotationen kommentiert und an Webformulare weitergeleitet werden; es benutzt Sql2o hinter den Kulissen; Es konzentriert sich auf Kotlin als einzige Zielsprache. Disclaimer: Ich bin der Autor. –