正如JPA所要求的那样, @Entity
类应该具有默认(非arg)构造函数,以便在从数据库中检索对象时实例化对象 .
在Kotlin中,在主构造函数中声明属性非常方便,如下例所示:
class Person(val name: String, val age: Int) { /* ... */ }
但是当非arg构造函数被声明为次要构造函数时,它需要传递主构造函数的值,因此需要它们的一些有效值,如下所示:
@Entity
class Person(val name: String, val age: Int) {
private constructor(): this("", 0)
}
如果属性具有比 String
和 Int
更复杂的类型,并且它们在主构造函数和 init
块中有很多代码,并且当参数被主动使用时 - 当它们通过反射重新分配时,大多数代码都是将要再次执行 .
此外,在构造函数执行后,不能重新分配 val
-properties,因此也不会失去不变性 .
所以问题是:Kotlin代码如何适应JPA而不需要代码重复,选择“神奇”的初始值和失去不变性?
附:除了JPA之外,Hibernate是否可以构造没有默认构造函数的对象?
9 回答
As of Kotlin 1.0.6 ,
kotlin-noarg
编译器插件为已使用选定注释注释的类生成合成默认构造函数 .如果使用gradle,则应用
kotlin-jpa
插件足以为使用@Entity
注释的类生成默认构造函数:对于Maven:
只需为所有参数提供默认值,Kotlin将为您创建默认构造函数 .
请参阅以下部分下方的
NOTE
框:https://kotlinlang.org/docs/reference/classes.html#secondary-constructors
@ D3xter对一个型号有一个很好的答案,另一个是Kotlin的一个叫做
lateinit
的新功能:当您确定某些内容将在构造时或很快之后(以及在第一次使用实例之前)填充值时,您将使用此方法 .
您将注意到我将
age
更改为birthdate
,因为您无法使用带有lateinit
的原始值,并且它们目前也必须是var
(将来可能会释放限制) .因此,对于不变性而言,这不是一个完美的答案,在这方面与其他答案一样 . 解决方案是插件到库,可以处理理解Kotlin构造函数和将属性映射到构造函数参数,而不需要默认构造函数 . Kotlin module for Jackson这样做,所以显然是可能的 .
See also: https://stackoverflow.com/a/34624907/3679676用于探索类似的选项 .
如果要为不同的字段重用构造函数,则需要初始值,kotlin不允许空值 . 因此,无论何时计划省略字段,请在构造函数中使用此表单:
var field: Type? = defaultValue
jpa不需要参数构造函数:
没有代码重复 . 如果您需要构造实体且仅设置年龄,请使用以下形式:
没有魔法(只是阅读文档)
没有办法像这样保持不变性 . 构造实例时必须初始化Vals .
一种没有不变性的方法是:
我已经和Kotlin JPA合作了很长一段时间,我已经创建了自己的想法如何编写实体类 .
我只是略微扩展你的初步想法 . 正如你所说,我们可以创建私有无参数构造函数并为基元提供默认值,但是当我们尝试使用另一个类时,它会变得有点混乱 . 我的想法是为你当前写的实体类创建静态STUB对象,例如:
当我有与TestEntity相关的实体类时,我可以轻松地使用我刚创建的存根 . 例如:
当然这个解决方案并不完美 . 您仍然需要创建一些不需要的样板代码 . 还有一个案例无法通过存根 - 一个实体类中的父子关系 - 很好地解决 - 像这样:
由于鸡蛋问题,此代码将产生NullPointerException - 我们需要STUB来创建STUB . 不幸的是,我们需要使这个字段可以为空(或类似的解决方案)以使代码有效 .
同样在我看来,Id作为最后一个字段(并且可以为空)是非常优化的 . 我们不应该手动分配它,让数据库为我们做 .
我并不是说这是完美的解决方案,但我认为它利用了实体代码的可读性和Kotlin功能(例如null安全性) . 我只希望将来发布JPA和/或Kotlin将使我们的代码更简单,更好 .
与@pawelbial类似,我使用了伴随对象来创建默认实例,但是不是定义辅助构造函数,而是使用默认构造函数args,如@iolo . 这样可以节省您必须定义多个构造函数并使代码更简单(尽管已授予,但定义“STUB”伴随对象并不能完全保持简单)
然后是与
TestEntity
相关的类正如@pawelbial所提到的,当构造函数运行时,自从STUB起_1158688_类"has a"
TestEntity
类时,这将不起作用 .我自己是一个小组,但似乎你必须显式初始化并回退到这样的null值
这些Gradle构建线帮助我:
https://plugins.gradle.org/plugin/org.jetbrains.kotlin.plugin.jpa/1.1.50 .
至少,它内置IntelliJ . 目前它在命令行上失败了 .
我有一个
和
var path:LtreeType不起作用 .