【问题标题】:Hibernate: cannot cascading delete unidirectional parent of children休眠:不能级联删除孩子的单向父母
【发布时间】:2017-06-30 16:40:59
【问题描述】:

当删除孩子的父母(在一对多的单向关系中)时,我不断收到这些错误。 当我先删除孩子时,一切正常。

我不需要/想要双向关系。

这是父母:

@Entity
@Table(name = "datagroup")
public class DataGroup implements java.io.Serializable {
    @Id
    @Column(name = "group_id", unique = true, nullable = false)
    private int         group_id;
    private String      name;

    @OneToMany( targetEntity=DataGroupItem.class, fetch=FetchType.LAZY, cascade = CascadeType.REMOVE)
    @JoinColumn(name="group_id")
    private List<DataGroupItem> dataGroupItems = new ArrayList<>( 0);
    ... setters and getters
}

这是孩子:

@Entity
@Table(name = "datagroupitems")
public class DataGroupItem implements java.io.Serializable {
    @Id
    @Column(name = "item_id", nullable = false)
    private int item_id;
    private String name;

    @Column(name = "group_id", nullable = false)
    private int group_id = 0; // only for (un)delete
    ... getters and setters
}

当我在控制器中删除父级时:

@RestController
@RequestMapping("/learner/groups")
public class LearnerSyncServices {
    @Autowired
    private IDataGroupRepository dataGroupRepository;
    @Autowired
    private IDataGroupItemRepository dataGroupItemRepository;
    ... 

    @RequestMapping( method= RequestMethod.DELETE, value="/{id}")
    public void delete(@PathVariable String id) {
        try {
            int idx = Integer.parseInt( id);
            dataGroupRepository.delete( idx);
        } catch (Exception e) {
            logger.error( "Cannot delete " + id + "  " + e.getMessage());
        }
    }

作为 JPA 版本,我拥有:Spring Boot 版本 4.1.3。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

删除至少有 1 个孩子的组会显示以下消息:

.. WARN  org.hibernate.engine.jdbc.spi.SqlExceptionHelper - SQL Error: 1048, SQLState: 23000
.. ERROR org.hibernate.engine.jdbc.spi.SqlExceptionHelper - Column 'group_id' cannot be null
.. INFO  org.hibernate.engine.jdbc.batch.internal.AbstractBatchImpl - HHH000010: On release of batch it still contained JDBC statements
.. ERROR nl.deholtmans.tjm1706.learner.LearnerSyncServices - Cannot delete 101  could not execute statement; SQL [n/a]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement

【问题讨论】:

  • 组的引用是nullable=false。您要么需要为每个孩子设置一个新的引用,要么使用级联删除每个孩子(如果需要的话)。
  • 您能否详细说明“nullable=false”以及您的两个选项?也许最好将其放在答案中(而不是评论)。首选是级联删除:删除组及其所有的孩子
  • 你试过CascadeType DELETE_ORPHAN吗?
  • 哦,它已被废弃,现在它的 @OneToMany(orphanRemoval = true)
  • 没有任何改变,仍然是一个错误。

标签: java spring hibernate jpa


【解决方案1】:

删除DataGroup 时,hibernate 首先尝试发出将删除父项的 SQL 语句,然后继续发出删除子项的语句。

删除父表时,datagroupitems 表中的外键必须设置为NULL 以保持 db 一致性(此时,对于 db 来说,子行也将被删除并不明显)。但是,它不能设置为NULL,因为您在架构定义中明确禁止它。

Hibernate 根本不知道它应该先删除子项,最后删除父项。您可以通过允许 group_id 列可以为空来解决此问题。

编辑如果您不使用“hbm2ddl.auto/javax.persistence.schema-generation.database.action”,请不要忘记重新创建/手动更新您的数据库架构。需要从数据库中删除 NOT NULL 约束才能使此解决方案起作用。

【讨论】:

  • 当我在孩子中设置这个时,我得到了同样的错误:@Column(name = "group_id") private int group_id = 0;或:@Column(name = "group_id", nullable = true)。
  • 我了解到您在执行更改后重新创建了架构?
  • 另外,您能否解释一下为什么首先需要在DataGroupItem 中映射group_id 列?你声称你不需要双向关系。我会尝试删除映射或将其设为 updatable=false 以查看问题是否消失
  • 请详细说明您的评论“重新创建了您的架构”。我不希望孩子向父母提及。所以,我不想在孩子(DataGroupItem)中有一个属性“DataGroup parentDataGroup”。
  • recreated your schema,我的意思是你确定CONSTRAINT group_id NOT NULL 在你将nullable=false 更改为nullable=true 后已经被删除了吗?例如,您的persistence.xml 中是否定义了hibernate.hbm2ddl.auto=update?如果您遇到 exact same 错误,那么似乎 NOT NULL 约束还没有被删除。尝试手动删除它
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-29
  • 2023-04-06
  • 2010-11-03
  • 1970-01-01
相关资源
最近更新 更多