Hibernate's cascading saving

Viewed 16

I am new to hibernate and i am trying to use its cascading capability. My domain is about stores and appointments. Every store has many appointments and every appointment is associated with one store(OneToMany relationship). Here are the classes declarations:

@Entity
@Table(name = "stores")
class Store(
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    var id: Long? = null,

    @Version
    var version: Long = 0,

    @OneToMany(mappedBy = "store", cascade = [CascadeType.PERSIST,CascadeType.REMOVE])
    var appointments: MutableList<Appointment> = mutableListOf(),
);

@Entity
@Table(name = "appointments")
class Appointment(
    @ManyToOne(cascade = [CascadeType.PERSIST])
    var store: Store,
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    var id: Long? = null,

    @Version
    var version: Long = 0
)

My service method uses spring repositories and does the following:

fun bookAppointment(newAppointment: NewAppointment): Appointment {
        Validators.validateEmail(newAppointment.customer.email)
        val store = storeRepository.findById(newAppointment.storeId).orElseThrow { EntityNotFoundException(Store::class.java) }

        val appointment = store.addAppointment(newAppointment)
        storeRepository.save(store)
        emailService.sendAppointmentBookedEmail(appointment)
        return appointment
    }

But something after save goes wrong. When I run in debug,i see that an appointment is added to the appointments collection with valid values(those that i as user inserted). But after the save call, store instance changes and the appointments collection also - all values of the previous appointment are set to null or 0, and only after this the appointment is saved to the database with the wrong data. What could be the problem?

1 Answers

Rather than resaving store (this will result in a merge which is why your are seeing different results when you add cascade.all because that includes cascade.merge). You should create an appointment repository and save appointment.

fun bookAppointment(newAppointment: NewAppointment): Appointment {
    Validators.validateEmail(newAppointment.customer.email)
    val store = storeRepository.findById(newAppointment.storeId).orElseThrow { EntityNotFoundException(Store::class.java) }

    val appointment = store.addAppointment(newAppointment)
    appointment.setStore(store);
    appointment = appointmentRepository.save(appointment)
    emailService.sendAppointmentBookedEmail(appointment)
    return appointment
}

// remove cascade from @ManytoOne

@Entity
@Table(name = "appointments")
class Appointment(
    @ManyToOne
    var store: Store,
Related