Неконтролируемое удаление в Spring Data и Hibernate - PullRequest
0 голосов
/ 20 февраля 2019

Я не эксперт по Hibernate, поэтому мой вопрос может быть тривиальным.

Я пишу механизм бронирования на событие.С помощью движка можно сделать регистрации , каждая из которых имеет определенное количество участников .С каждой регистрацией может быть связано одно или несколько платежей .

Для каждой регистрации можно сделать несколько бронирований для номеров.Бронирование может быть сделано для части комнаты (например, для двух участников, которые хотят проживать в четырехместном номере) или для всей комнаты.Каждая комната может иметь несколько номеров (например, четырехместных, трехместных или двухместных), соответствующих определенному типу номеров .Когда резервирование для номера выполнено, выбранный тип номера и номер соединяются посредством назначения номера , связанного с резервированием.

Чтобы кодировать это весной, янастроить следующие классы моделей:

Registration.java

@Entity
@Table(name = "registrations")
@Data
public class Registration {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id")
    private Long id;

    // other fields

}

Participant.java

@Entity
@Table(name = "participants")
@Data
public class Participant {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id")
    private Long id;

    @ManyToOne(targetEntity = Registration.class)
    @JoinColumn(name = "registration_id")
    private Registration registration;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "reservation_id")
    private Reservation reservation;

    // other fields
}

Reservation.java

@Entity
@Table(name = "reservations")
@Data
public class Reservation {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id")
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "room_assignment_id")
    private RoomAssignment roomAssignment;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "registration_id")
    private Registration registration;


    @OneToMany(fetch = FetchType.LAZY)
    @JoinColumn(name = "reservation_id")
    private List<Participant> participants;

    // other fields

}

RoomAssignment.java

@Entity
@Table(name = "room_assignments")
@Data
public class RoomAssignment {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id")
    private Long id;


    @OneToOne(fetch = FetchType.LAZY, mappedBy = "assignment", cascade = CascadeType.ALL)
    private Room room;

    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "room_type_id", nullable = false)
    private RoomType roomType;


    @OneToMany(fetch = FetchType.LAZY)
    @JoinColumn(name = "room_assignment_id")
    private List<Reservation> reservations;

}

Room.java

@Entity
@Table(name = "rooms")
@Data
public class Room {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id")
    private Long id;

    @Column(name = "room_name")
    private String roomName;

    @OneToMany(fetch = FetchType.LAZY )
    @JoinColumn(name = "room_id")
    private List<RoomArrangement> roomArrangements;

    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "assignment_id")
    private RoomAssignment assignment;

}

И, наконец, RoomArrangement.java

@Entity
@Table(name = "room_arrangements")
@Data
public class RoomArrangement {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id")
    private Long id;

    @ManyToOne(targetEntity = RoomType.class)
    @JoinColumn(name = "room_type_id", nullable = false)
    private RoomType roomType;

    @ManyToOne(targetEntity = Room.class)
    @JoinColumn(name = "room_id", nullable = false)
    private Room room;

    @Column(name = "priority")
    private Integer priority;

}

Все классы моделей имеют свои соответствующие классы репозитория, которые я не будудобавьте сюда, поскольку они просто содержат имена методов, которые вы можете видеть из кода.

В настоящее время я пишу процедуру для удаления регистрации.Для этого я исключаю всех участников и все платежи, затем для каждого бронирования я вижу, является ли он единственным для соответствующего назначения номера, и в этом случае я также отменяю назначение номера, и я отменяю резервирование и, наконец,Регистрация.Я закодировал эту часть в этом методе:

@Override
public void deleteRegistration(Registration registration) {
    // Deleting payments
    paymentRepository.deleteAll(paymentRepository.findByRegistration(registration));

    // Deleting participants
    participantRepository.deleteAll(participantRepository.findByRegistration(registration));

    List<Reservation> reservations = reservationRepository.findByRegistration(registration);
    for (Reservation res : reservations) {
        RoomAssignment assignment = roomAssignmentRepository.findByReservationsContains(res);

        if (reservationRepository.findByRoomAssignment(assignment).size() == 1) {
            reservationRepository.delete(res);

            Room room = roomRepository.findByAssignment(assignment);
            room.setAssignment(null);
            roomRepository.save(room);

            roomAssignmentRepository.delete(assignment);
        } else {
            reservationRepository.delete(res);
        }
    }

    registrationRepository.delete(registration);
}

Результат довольно странный: когда исполнение прибывает в roomAssignmentRepository.delete (assignment);вызов прерывается с помощью DataIntegrityViolationException с сообщением

Column 'room_id' cannot be null

Я пытался регистрировать вызовы в спящем режиме, и один из них определенно странен для моих глаз.

Здесь я перечисляю их с помощьюсоответствующий вызов java

paymentRepository.deleteAll (не было никаких платежей за эту регистрацию)

select payment0_.id as id1_1_, payment0_.amount as amount2_1_, payment0_.paypal_order_id as paypal_o3_1_, payment0_.registration_id as registra5_1_, payment0_.type as type4_1_ from payments payment0_ where payment0_.registration_id=?

memberRepository.deleteAll

select participan0_.id as id1_0_, participan0_.birth_date as birth_da2_0_, participan0_.birth_place as birth_pl3_0_, participan0_.email as email4_0_, participan0_.facebook_profile as facebook5_0_, participan0_.first_name as first_na6_0_, participan0_.first_time as first_ti7_0_, participan0_.food_intolerances as food_int8_0_, participan0_.food_preferences as food_pre9_0_, participan0_.gender as gender10_0_, participan0_.last_name as last_na11_0_, participan0_.other_food_notes as other_f12_0_, participan0_.registration_id as registr13_0_, participan0_.reservation_id as reserva14_0_ from participants participan0_ where participan0_.registration_id=?
delete from participants where id=?

bookingRepository.findByRegistration

select reservatio0_.id as id1_3_, reservatio0_.monday as monday2_3_, reservatio0_.registration_id as registra4_3_, reservatio0_.room_assignment_id as room_ass5_3_, reservatio0_.thursday as thursday3_3_ from reservations reservatio0_ where reservatio0_.registration_id=?

roomAssignmentRepository.findByReservationsContains

select roomassign0_.id as id1_5_, roomassign0_.room_type_id as room_typ2_5_ from room_assignments roomassign0_ where ? in (select reservatio1_.id from reservations reservatio1_ where roomassign0_.id=reservatio1_.room_assignment_id)
select room0_.id as id1_7_0_, room0_.assignment_id as assignme3_7_0_, room0_.room_name as room_nam2_7_0_ from rooms room0_ where room0_.assignment_id=?

bookingRepository.delete

select reservatio0_.id as id1_3_, reservatio0_.monday as monday2_3_, reservatio0_.registration_id as registra4_3_, reservatio0_.room_assignment_id as room_ass5_3_, reservatio0_.thursday as thursday3_3_ from reservations reservatio0_ where reservatio0_.room_assignment_id=?
update participants set reservation_id=null where reservation_id=?
delete from reservations where id=?

roomRepository.findByAssignment

select room0_.id as id1_7_, room0_.assignment_id as assignme3_7_, room0_.room_name as room_nam2_7_ from rooms room0_ where room0_.assignment_id=?

roomRepository.save

update rooms set assignment_id=?, room_name=? where id=?

roomAssignmentRepository.delete

update reservations set room_assignment_id=null where room_assignment_id=?
update room_arrangements set room_id=null where room_id=?

Это последнее обновление room_arrangements set room_id = null, где room_id =? , конечно, обновление SQL, нарушающее ненулевое ограничение.

После этой длительной подготовки возникает вопрос: почему Hibernate делает это последнее обновление, так как я не изменяю никакие room_arrangement в тем не мение?В момент этого вызова я изменяю класс RoomAssignment, который даже не связан с RoomArrangement.

1 Ответ

0 голосов
/ 20 февраля 2019

симпатичный.Написав вопрос, я понял, что, как мы говорим в Италии, дьявол кроется в деталях.

Копирование и вставка материалов из примеров в Интернете заставили меня неправильно комментировать отношения между RoomAssignment и Room.

@OneToOne(fetch = FetchType.LAZY, mappedBy = "assignment", cascade = CascadeType.ALL)
    private Room room;

Проблема, конечно, была связана с CascadeType.ALL: когда я удалял назначение, Hibernate также пытался удалить Комнату, а при этом очищал RoomType, очищая внешний ключ -что, конечно, вызвало ошибку.

Урок, который я могу извлечь из этого: будьте осторожны при копировании и вставке из Интернета:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...