我有一个Kotlin项目..
我添加了complete code to github,所以你可以下载它来玩。
有2个实体:
带
@Entity
data class Band(
@Id
@Setter(AccessLevel.NONE)
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Schema(hidden = true)
val id: Int? = null,
var name: @NotEmpty(message = "name must not be empty") String? = null,
@OneToMany(fetch = FetchType.EAGER,
mappedBy = "band",
cascade = [CascadeType.ALL])
val links: Set<Link> = mutableSetOf()
)
链接
@Entity
data class Link(
@Id
@Setter(AccessLevel.NONE)
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Schema(hidden = true)
val id: Int? = null,
var url: String? = null,
@ManyToOne(fetch = FetchType.EAGER, cascade = [CascadeType.ALL])
@JoinColumn(name = "band_id", nullable = true)
var band: Band? = null
)
SQL如下所示:
create table band
(
id serial PRIMARY KEY not null,
name varchar(100) not null
);
create table link
(
id serial PRIMARY KEY not null,
band_id int,
url varchar(100) not null,
CONSTRAINT "fk_band_links" FOREIGN KEY ("band_id") REFERENCES "band" ("id")
);
我为我的测试创建了一个这样的乐队(在BandUtils.kt
中)
fun createBandWithLinks(): Band {
val link1 = Link()
link1.url = "https://fb.com/"
val link2 = Link()
link2.url = "https://twitter.com/"
return Band(
name = "Band with links",
links = mutableSetOf(link1,link2),
)
}
保存数据时:
bandRepository!!.save(BandUtils.createBandWithLinks())
我希望,链接和乐队都被保存了!这很有效。
但我看不到链接表中的带。
我以前在Java中做过同样的事情,我也看到Baeldung的例子是这样工作的。
Kotlin和Java之间有什么区别吗?
1条答案
按热度按时间0yg35tkg1#
问题1.持久化双向关系Band=Link
在双向关系的情况下,Hibernate(或JPA实现)只关心关联的拥有方。拥有方是不具有
mappedBy
属性的那一方!因此,如果我们只调用
band.links = LinkUtils.createListOfLinks()
,则Band
将不会链接到新的Link
实体,因为这不是关系的拥有/跟踪方。您需要显式地将
Band
设置为Link
,调用link.band = band
,因为这是关系的拥有方。当使用
mappedBy
时,开发人员有责任知道什么是拥有方,并更新关系的正确方,以便触发新关系在数据库中的持久性。Java和Kotlin没有什么区别,都是JPA规范。
解决方案1:从双方设置关系
更正实用程序以从两侧设置关系
解决方案2:更改关系的拥有方(不推荐)
不需要改变你的效用。
删除
OneToMany
的mappedBy
,添加JoinColumn
将
JoinColumn(insertable = false, updatable = false)
与ManyToOne
相加实体定义
在你的Baeldung文章中,这个问题在第6项中描述。
问题2. toString和hashCode的双向关系数据类循环依赖
当您正确创建实体时,在持久化过程中会收到
StackOverflow
错误,因为您有双向关系和定义为data class
的实体。Kotling将生成不正确的hashCode
实现,该实现在执行双向实体时会进入无限循环。解决方案1:Lombok岛
使用
Lombok
代替data class
并忽略一个关系边第一个
解决方案2:将导致循环依赖关系的属性移动到数据类主体
请参阅详细信息Kotlin - Data class entity throws StackOverflowError
更新
为什么更改拥有方不是一个好的解决方案?
它对生成的查询计数的影响以及因此对性能的影响。
3个查询在拥有方为
ManyToOne
的情况下生成:5个查询在拥有方为
OneToMany
的情况下生成: