2016-06-09 1 views
5

Большинство Котлин JPA пример кода выглядит следующим образомKotlin с JPA/Hibernate: без ленивой загрузки без `open`?

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

или даже

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

Теперь Hibernate User Guide, и я думаю, также несколько других ORMs, заявляют, что они обычно хотят, чтобы создать прокси или иным образом расширить класс модели, но чтобы разрешить в Kotlin класс должен быть явно определен open. В настоящее время это невозможно с классами данных, и я полагаю, исходя из собственного опыта, что большинство людей не думают об этом при написании сущностей JPA в Котлине.

Таким образом, чтобы прийти на мой вопрос (это StackOverflow в конце концов), это достаточно, чтобы сделать

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

или же мы на самом деле нужно сделать

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

не напрасно препятствовать ORM при правильной работе?
Если это действительно вредно, мы должны, вероятно, предложить добавить предупреждение IntelliJ IDEA, что если класс имеет аннотацию @Entity, ее следует определить open.

+0

Я не вижу, как здесь применимо слово «вредный». Не могли бы вы уточнить его использование или удалить его из вопроса, если это не важно? – voddan

+0

Главным образом это факт, что по крайней мере Hibernate не может использовать классы с ленивой загрузкой, которые являются окончательными или имеют окончательные методы доступа, а использование классов данных для JPA часто выглядит как хорошая вещь, но может на самом деле повредить производительность, поскольку они являются окончательными по определению (в данный момент, по крайней мере, слышал, что это может измениться). Название очень щедрое, потому что я думал, что это должно быть чем-то более общеизвестным и предотвращать, например, приложения, перенесенные в Kotlin с худшей производительностью, чем Java-партнеры, а затем пользователи обвиняют Kotlin:/ – johnp

+0

Спасибо, что перефразировали вопрос! – voddan

ответ

6

В учебнике вы предоставили определяет:

Класс объект должен иметь открытый или защищенный конструктор без аргументов ... Интерфейс может не быть определен как объект ... Класс объект не должен быть окончательным , Никакие методы или постоянные переменные экземпляра класса сущности не могут быть окончательными.

Kotlin классы следуют за соглашением JavaBeans для сеттеров/геттеров.

Если ОРМ имеет требования, как указано выше, то вы действительно должны указать open на класс и его методы:

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

значения по умолчанию для всех параметров конструктора позволяют Котлин генерировать дополнительный пустой конструктор. В качестве альтернативы вы можете предоставить его в качестве вторичного конструктора:

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

Обратите внимание, что open val создает частное последнее поле и открытый добытчик. Если этого недостаточно, используйте аннотации, такие как @JvmField open val name.

ORM, как у вас, есть дополнительное трение с кодом Котлина из-за сомнительных шаблонов дизайна, которые они используют (например, для того, чтобы сделать все не финальным).

Хорошим вариантом является использование ОРМ, специфичного для Kotlin. Например, Exposed поддерживается JetBrains и используется для некоторых своих продуктов, что говорит само за себя. Другим вариантом является Ebean, который официально поддерживает Kotlin (спасибо @johnp)

+1

Спасибо за ваш ответ! Одна из вещей, которая показалась мне странной, заключалась в том, что конечные классы не могут быть ленивы загружены в Hibernate, и я подумал, что это может серьезно повредить работе, если не принять во внимание. Я лично перешел на [Ebean] (https://ebean-orm.github.io/) пару недель назад, потому что он явно упоминает Котлина и имеет более низкий входной барьер, чем Hibernate, но я еще не слышал об Exposed и обязательно посмотрим на это. – johnp

+0

Lazy loading означает, что Hibernate должен загружать данные только в том случае, если в первый раз вызывается геттер. Однако геттер уже реализован программистом (как простое поле)! Таким образом, Hibernate должен изменить функциональность этого метода, чтобы он опросил JDBC во время разговора. Вы можете изменить метод, изменив байт-код на этапе компиляции или динамически расширяя класс и переопределяя сеттеры. –

+0

Если вы хотите рассмотреть ORM, специфичный для Kotlin, https://github.com/mvysny/vok-orm может быть хорошим вариантом. Он по-прежнему использует POJO, которые могут, например, аннотироваться аннотациями JSR303 и переходить к веб-формам; он использует Sql2o за кулисами; он фокусируется на Котлине как на единственном целевом языке. Отказ от ответственности: Я автор. –