为什么不能以级联方式删除数据?

问题描述 投票:1回答:1

问题是,当我想删除用户时,我在Spring Boot中会遇到这样的错误:

java.sql.SQLIntegrityConstraintViolationException:无法删除或更新父行:外键约束失败(32506632_pambadge,CONSTRAINT FK4aamfo6o0h5ejqjn40fv40jdw外国关键字(user_id)参考userid) )

我猜我需要以级联方式删除数据。因此,我已经将CascadeType.REMOVE值放置到@ OneToOne注释中,但这是行不通的:

徽章实体

@Entity
@Data
@Table(name = "badge")
@AllArgsConstructor
@NoArgsConstructor
public class Badge {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @JsonManagedReference
    @ManyToMany(mappedBy = "badges", fetch = FetchType.LAZY)
    private List<Reader> readers;

    @OneToOne(cascade = CascadeType.REMOVE, orphanRemoval=true)
    @JoinColumn(name = "user_id")
    private User user;

    private String number;

    @Lob
    @Basic(fetch = FetchType.LAZY)
    private byte[] photo;
}

用户实体

@Entity
@Data
@Table(name = "user")
@AllArgsConstructor
@NoArgsConstructor
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    private String lastname;

    private String pesel;

    private String email;

    private String telephone;

    private Integer age;

    private String gender;
}

读者实体

@Entity
@Data
@Table(name = "reader")
@AllArgsConstructor
@NoArgsConstructor
public class Reader {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @JsonBackReference
    @ManyToMany(fetch = FetchType.LAZY)
    private List<Badge> badges;

    private String department;

    private String room;

    private Boolean status;
}

加载初始数据的类

@Component
public class DataLoader implements ApplicationRunner {

    @Autowired
    private UserService userService;

    @Autowired
    private BadgeService badgeService;

    @Autowired
    private ReaderService readerService;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        User user1 = new User(null, "Jan", "Kowal", "11111111111", "[email protected]", "+48111111111", new Integer(23), "male");
        userService.saveUser(user1);

        Reader reader1 = new Reader(null, null, "Warehouse", "207A", new Boolean("true"));

        Badge badge1 = new Badge(null, Arrays.asList(reader1), user1, "738604289120", null);
        badgeService.saveBadge(badge1);

        reader1.setBadges(Arrays.asList(badge1));
        readerService.saveReader(reader1);
    }

}

用于删除用户的端点-它使用存储库来扩展CrudRepository并使用默认的删除行为。

@DeleteMapping("/deleteUserById/{id}")
private void deleteUserById(@PathVariable Long id) {
    userService.deleteUserById(id);
}

phpmyadmin中的数据库结构enter image description here

我的目标是删除用户和与其关联的徽章,然后删除reader_badges表中的行。

spring-boot spring-data-jpa cascade
1个回答
1
投票
TL; DR:

如果要从用户删除相关的Badge实例,则必须将CascadeType.REMOVE添加到用户关系规范中,当然还要在User中声明Badge实例变量/属性。课。

详细说明

当您尝试从表中删除用户实例时发生错误,因为它是父行。徽章行中的FK约束“ user_id”将在每次编辑关系时查看该关系上的数据完整性。删除User实例将导致Badge实例无法在User表中找到他的相关主键“ id”,因此约束消失了,这就是异常的原因。

实际上映射到数据库的关系是:

徽章取决于用户

不是相反。

因此,如果您删除已声明的用户

cascade = CascadeType.REMOVE

在级联策略中,将达到目的。但事实并非相反。因为级联策略用于将级联删除从父级“级联”到子级(依赖/依赖于父级的实体)。因此,在您的情况下,从用户到徽章。

因为徽章实际上是您关系中的弱者。

Obs:如果您不需要相反的行为,即在删除Badge之后删除User实例,则可以轻松地删除该行:

cascade = CascadeType.REMOVE

来自徽章级联策略。

© www.soinside.com 2019 - 2024. All rights reserved.