【问题标题】:Kotlin with JPA/Hibernate: no lazy-loading without `open`?带有 JPA/Hibernate 的 Kotlin:没有“open”就没有延迟加载?
【发布时间】:2016-10-10 13:25:16
【问题描述】:

大多数 Kotlin JPA 示例代码如下所示

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

甚至

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

现在,Hibernate User Guide 以及其他几个 ORM 声明他们通常想要创建代理或以其他方式扩展模型类,但要允许在 Kotlin 中明确定义该类 open。目前这对于数据类来说是不可能的,我认为,根据我自己的经验,大多数人在用 Kotlin 编写 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。

【问题讨论】:

  • 我不明白“有害”这个词在这里是如何适用的。如果它不重要,您能否澄清它的用途或将其从问题中删除?
  • 主要是这样一个事实,至少 Hibernate 不能延迟加载最终类或具有最终访问器方法的类,并且为 JPA 使用数据类通常看起来是一件好事,但实际上会损害性能,因为根据定义它们是最终的(至少目前;听说可能会改变)。标题很容易点击,因为我认为这应该是更广为人知的东西,并防止例如移植到 Kotlin 的应用程序的性能比 Java 对应物差,然后用户指责 Kotlin:/
  • 感谢您解释问题!

标签: hibernate jpa orm lazy-loading kotlin


【解决方案1】:

kotlin allopen 编译器插件在这里可能值得一提。

<pluginOptions>
    ...
    <option>all-open:annotation=javax.persistence.Entity</option>
</pluginOptions>

这将使所有带有 @Entity 注释的类打开。

【讨论】:

    【解决方案2】:

    您提供的教程指定:

    实体类必须有一个公共或受保护的无参数构造函数...接口不能指定为实体...实体类不能是最终的。实体类的任何方法或持久实例变量都不能是最终的。

    Kotlin 类遵循 JavaBeans 的 setter/getter 约定。

    如果您的 ORM 有上述要求,那么您确实必须在类及其方法上指定 open:

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

    所有构造函数参数的默认值允许 Kotlin 生成额外的空构造函数。或者,您可以将其作为辅助构造函数提供:

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

    请注意,open val 创建了一个私有的 final 字段和一个开放的 getter。如果这还不够,请使用 @JvmField open val name 之类的注释。

    像你使用的那样的 ORM 与 Kotlin 代码有额外的摩擦,因为它们使用的设计模式有问题(比如让所有东西都不是最终的)。

    一个不错的选择是使用特定于 Kotlin 的 ORM。例如,Exposed 由 JetBrains 支持并用于其某些产品,这不言而喻。另一个选项是Ebean,它正式支持 Kotlin(感谢 @johnp)

    【讨论】:

    • 感谢您的回答!让我感到奇怪的一件事是最终类不能在 Hibernate 中延迟加载,我认为如果不考虑这可能会严重影响性能。几周前我个人切换到Ebean,因为它明确提到了Kotlin,并且入门门槛比Hibernate低,但我还没有听说过Exposed,一定会看看。
    • 延迟加载是指Hibernate只有在第一次调用getter时才需要加载数据。但是,getter 已经由程序员实现(作为简单的字段读取)!因此,Hibernate 需要更改该方法的功能,以便在调用时轮询 JDBC。您可以通过在编译阶段修改字节码或通过动态扩展类并覆盖 setter 来更改方法。
    • 如果您愿意考虑使用 Kotlin 特定的 ORM,github.com/mvysny/vok-orm 可能是一个不错的选择。它仍然使用 POJO,例如使用 JSR303 注释进行注释并传递给 Web 表单;它在幕后使用 Sql2o;它专注于将 Kotlin 作为唯一的目标语言。免责声明:我是作者。
    猜你喜欢
    • 1970-01-01
    • 2013-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-21
    • 1970-01-01
    • 2019-04-28
    相关资源
    最近更新 更多