尝试使用 JoinTable 清除 OneToOne 关系时违反外键约束

foreign key constraint violation when trying to clear a OneToOne relationship using a JoinTable

提问人:6006604 提问时间:11/17/2023 最后编辑:6006604 更新时间:11/17/2023 访问量:32

问:

我有以下两个实体:

@Entity
public class RoomEntity {
    @OneToOne
    @JoinTable(
        name = "room_camera_association",
        joinColumns = {@JoinColumn(name = "room_id")},
        inverseJoinColumns = {@JoinColumn(name = "camera_id")}
    )
    private CameraEntity camera;

...和:

@Entity
public class CameraEntity {
    @OneToOne(mappedBy = "camera")
    private RoomEntity room;

...关联表的定义如下:

CREATE TABLE room_camera_association
(
    camera_id UUID NOT NULL,
    room_id UUID NOT NULL,
    PRIMARY KEY (camera_id, room_id),
    CONSTRAINT fk_camera FOREIGN KEY (camera_id) REFERENCES camera(id),
    CONSTRAINT fk_room FOREIGN KEY (room_id) REFERENCES room(id),
    CONSTRAINT uk_rca_camera_room UNIQUE (camera_id, room_id)
);

当我删除房间时,我不想删除相机。同样,如果我删除摄像机,我不想删除房间。

当我执行以下代码时:

        for (RoomEntity room: getRooms()) {
            CameraEntity camera = room.getCamera();
            if (camera != null) {
                log.info("Removing camera {} association for room {}", camera.getName(), room.getName());
                room.setCamera(null);
                camera.setRoom(null);
                roomRepository.save(room);
                cameraRepository.save(camera);
            }

...然后执行以下操作:

roomRepository.delete(room);

...我收到以下异常:

2023-11-16 12:50:10.959 ERROR 1641464 --- [           main] o.h.engine.jdbc.spi.SqlExceptionHelper   : ERROR: update or delete on table "room" violates foreign key constraint "fk_room" on table "room_camera_association"
  Detail: Key (id)=(385a510c-bd26-4f89-8077-6e6b9aa78e31) is still referenced from table "room_camera_association".

我错过了什么?

Java Spring-Boot JPA

评论


答:

0赞 Shubham Bansal 11/17/2023 #1

发生这种情况是因为您指定了 (cascade = {CascadeType.ALL})。

尝试将其更改为(cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH, CascadeType.DETACH})

这是因为您不希望 CascadeType.REMOVE 生效。

在移除空间之前,还可以尝试通过以下方式移除room_camera_association -entityManager.createNativeQuery("DELETE FROM room_camera_association WHERE room_id = :roomId").setParameter("roomId", room.getId()).executeUpdate(); roomRepository.delete(room);

评论

0赞 6006604 11/17/2023
实际上,它是在没有级联的情况下发生的。那是在我的帖子中无意中。我已经删除了它。但我没有尝试过 REFRESH 和 DETACH。让我试试。
0赞 6006604 11/17/2023
我收到同样的错误。
0赞 Shubham Bansal 11/17/2023
好吧,这种情况正在发生,因为room_id和camera_id仍然存在room_camera_association。因此,在删除房间或摄像头之前,您必须通过执行以下操作来删除room_camera_association - entityManager.createNativeQuery(“DELETE FROM room_camera_association WHERE room_id = :roomId”).setParameter(“roomId”, room.getId()).executeUpdate();roomRepository.delete(房间);
0赞 6006604 11/17/2023
JPA 不应该处理从@JoinTable中删除数据吗?
0赞 Shubham Bansal 11/17/2023
缺省情况下,JPA 不管理联接表上的关联。在这种情况下,该关系由 RoomEntity 和 CameraEntity 拥有。此外,级联不会删除手动管理的联接表,就像您的情况一样room_camera_association
0赞 6006604 11/17/2023 #2

我弄清楚发生了什么。我们还设置了触发器来审核正在修改或删除的数据。触发功能的设置如下:

INSERT INTO camera_association_log
    VALUES (NEW.*, 'DELETE'); RETURN NEW;

...触发因素是.BEFORE DELETE ON

这有效地防止了删除的发生,但这是悄无声息地发生的。当我将函数切换到 并将触发器切换到 时,此代码开始工作:RETURN OLDRETURN OLD

  room.setCamera(null);
  camera.setRoom(null);
  roomRepository.save(room);
  cameraRepository.save(camera);

...自动从关联表中删除记录,并允许后续文件室删除工作。