1

I'm using Kotlin in a Spring Boot project. I have a @ManyToMany relationship between Show and Product.

Show entity :

@Entity
@Table(name = "shows")
data class Show(
    @Id
    val id: String,
    
    @ManyToMany(cascade = [PERSIST])
    @JoinTable(
        name = "shows_products",
        joinColumns = [JoinColumn(name = "show_id")],
        inverseJoinColumns = [JoinColumn(name = "product_id")],
    )
    val products: Set<Product> = emptySet(),
)

Product entity :

@Entity
@Table(name = "products")
data class Product(
    @Id
    val id: String,
    
    @ManyToMany(cascade = [PERSIST], mappedBy = "products")
    @JsonBackReference
    var shows: Set<Show> = emptySet()
)

I have also created the corresponding repositories. I want to delete a show from the DB, without deleting the products attached to it. The problem that I've encountered is when I call 'showRepository.delete(show)'. If that show doesn't have any products attached to it, then it's deleted as expected. But if it has some products attached to it, the show is not deleted, but no exception is thrown. Additionally, the tests of the repository are not catching this :

    @Test
    fun `delete show with product`() {
        productRepository.save(aProduct)
        showRepository.save(aShow.copy(products = setOf(aProduct)))
        assertThat(showRepository.findByIdOrNull(aShow.id)).isNotNull
        assertThat(productRepository.findByIdOrNull(aProduct.id)).isNotNull

        showRepository.deleteById(aShow.id)
        assertThat(showRepository.findByIdOrNull(aShow.id)).isNull()
    }

I did some stackoverflowing, and I found these :

But I still don't understand it and how to implement it, especially if I want to keep the immutability in Kotlin classes.

Also, it started working as expected after removing the product relationship part:

@Entity
@Table(name = "products")
data class Product(
    @Id
    val id: String,
)

If someone please could help me understand these :

  • How to remove an entry properly from a ManyToMany relationship, in both cases, bi and unidirectional ?
  • Why no exception was thrown ?
  • Why the tests didn't catch what happened in the prod
  • How to implement a good solution for this in Kotlin
Ismaïl
  • 60
  • 1
  • 7

1 Answers1

0

You have cascade persist set on the 'other' side of the relationship. As soon as one of those Product instances that reference your 'deleted' Show instance is processed by the persistence context - anywhere - it will cause that show to be persisted, essentially undoing your delete. Remove then persist in the same context/transaction is pretty much a no-op except for the operations cascading over relationships. Maybe remove the cascade setting from Product->Show, or you deference the show from all Products before or during the removal process to keep your object model in synch with the database –

Chris
  • 20,138
  • 2
  • 29
  • 43