【问题标题】:Hibernate OneToMany wrong binding from parent从父级休眠 OneToMany 错误绑定
【发布时间】:2017-09-06 06:22:27
【问题描述】:

我有一个用 Kotlin 编写的简单 REST spring boot 应用。

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

我只有一个控制器操作,并且想将我的所有模型保存在一个请求中,如下所示:

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

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

但是当我添加一些 Header 列表时 - Hibernate 在 DB 中添加了额外的 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)

【问题讨论】:

    标签: spring-boot kotlin hibernate-onetomany


    【解决方案1】:

    我猜这是因为在您的Header 中,每次创建Header 的实例时,您都会创建新的Channel。此外,您将CascadeType 设置为ALL,这意味着这个新创建的Channel 也会被持久化。

    您可以将Headerchannel的类型设置为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
    

    【讨论】:

    • 你的意思是这样的:var channel: Channel? = null 但如何设置channel_id
    • @qwert_ukg 你能发布你是如何保存这些实体的吗?之后我更新我的答案。谢谢
    • 无法理解如何分配channel?你的意思是我应该手动构建Map 对象?
    • 你能根据我的数据做一个简短的例子吗?
    • 我是从请求数据手动创建我的Map 对象(但如果它被杰克逊反序列化为同一个对象,则看不到区别),在这种情况下我的channel_id 是@987654343 @ 在Header 行中。但行是单行
    【解决方案2】:

    回答

    找到here

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

    【讨论】:

      猜你喜欢
      • 2019-12-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-01
      • 1970-01-01
      • 2023-04-06
      • 1970-01-01
      相关资源
      最近更新 更多