来自父

时间:2017-09-06 06:22:28

标签: spring-boot kotlin hibernate-onetomany

我在Kotlin上编写了一个简单的REST Spring启动应用程序。

它有下一个架构:Map hasOne ChannelChannel hasMany Headers

我只有一个控制器动作,并希望将所有模型保存在一个请求中,如下所示:

{
    "channel": {
        "headers": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
        ]
    }
}

如果未设置标题,则所有模型都正确关联且数据库插入顺序也正确:首先创建Channel,然后使用此Map创建Channel

但是当我添加一些Header列表 - Hibernate在数据库中生成额外的Channel (ID = 2)行并将所有Header模型绑定到此渠道(ID = 2)

地图模型:

...
@ManyToOne(cascade = arrayOf(CascadeType.ALL))
@JoinColumn(name = "channel_id")
var channel: Channel = Channel(),
...

渠道模型:

...
@OneToMany(mappedBy = "channel", cascade = arrayOf(CascadeType.ALL), )
var headers: MutableSet<Header> = mutableSetOf(),
...
@JsonIgnore
@OneToMany(mappedBy = "channel", cascade = arrayOf(CascadeType.ALL))
var maps: MutableSet<Map> = mutableSetOf(),
...

标头型号:

...
@JsonIgnore
@ManyToOne(cascade = arrayOf(CascadeType.ALL))
@JoinColumn(name = "channel_id")
var channel: Channel = Channel(),
...

也许应该修复一些注释。很高兴听到任何建议。谢谢大家!

更新

保存那样的模型:

@PostMapping("/maps")
fun post(@RequestBody body: Map) = repo.save(body)

更新2

如果手动创建对象,并将必要的属性类型声明为nullable - channel_id将为null

将此代码添加到操作

val channel = Channel(
        ...
)

body.channel!!.headers.forEach {
    val header = Header(
            name = it.name,
            value = it.value
    )

    channel.headers.add(header)
}

val map = Map(
        channel = channel
)

return repo.save(map)

2 个答案:

答案 0 :(得分:1)

我想这是因为在Header中,每次创建Channel的实例时,您都会创建新的Header。此外,您将CascadeType设置为ALL,这意味着此新创建的Channel也会保留。

您可以将channelHeader的类型设置为Channel?,然后设置相应的channel

修改 要回复评论中的问题:channel_id将在您分配相应的channel后自动设置并保存此Header

编辑2 首先,我建议编辑模型:

<强>地图

var channel: Channel? = null

和标题:

var channel: Channel? = null

代码的相关部分:

val channel = ... // your Channel entity that is already persisted, for example map.channel (if map was saved before)
val header = Header(..., channel, ...) // create a new Header and set the channel
channel.headers.add(header) // it's bidirectional
repo.save(channel) // this should be enough as you have CascadeType.ALL set, so header should be persisted automatically

答案 1 :(得分:1)

<强> ANSWER

它找到了here

刚从集合属性中删除mappedBy = "channel"并添加@JoinColumn(name = "channel_id")