janlan
janlan

Reputation: 477

How to remove children from parent entity record in JPA?

I have Product entity and ProductRating entity, each Product can have many ProductRatings. When Product is deleted I want to have associated ratings deleted too, but nothing works so far (also orphanRemoval set to true)...

Classes:

@Getter
@Setter
@Entity
@Table(name = "PRODUCT")
public class Product extends AbstractEntity<Long> {

    @Column(nullable = false)
    private String name;

    private String description;

    @Column(nullable = false)
    @Min(value = 0)
    private Float cost;

    @OneToMany(mappedBy = "product",
            orphanRemoval = true, cascade = CascadeType.PERSIST,
            fetch = FetchType.EAGER)
    //@OnDelete(action = OnDeleteAction.CASCADE)
    @Fetch(value = FetchMode.SELECT)
    private Set<ProductRating> productRatings;

}
@Getter
@Setter
@Entity
@Table(name = "PRODUCT_RATING")
public class ProductRating extends Rating {

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "product_id")
    @NotNull(message = "Rating must be in context of Product")
    private Product product;
}

After Product deletion ratings stay with deleted Product's ID

AbstractEntity implementation:

@Getter
@Setter
@MappedSuperclass
public abstract class AbstractEntity<I> implements Serializable {
    private static final long serialVersionUID = 1700166770839683115L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "ID", unique = true, nullable = false)
    private I id;

}

Upvotes: 1

Views: 193

Answers (2)

janlan
janlan

Reputation: 477

My alternative approach to fix this problem is to:

  • On parent-side relation create method with @PreRemove annotation
  • in this method iterate over collection with @[One/Many]ToMany annotation and call delete(obj) method for corresponding repository on child
  • On child-side relation create method with @PreRemove annotation
  • In this method set parent to null

Upvotes: 0

pepevalbe
pepevalbe

Reputation: 1380

In the @OneToMany relation you need to add the cascade type delete: cascade = {CascadeType.PERSIST, CascadeType.REMOVE}

Or if you don't mind having all cascade types you can just put: cascade = CascadeType.ALL

EDIT:

Also check the name of the Product primary key in the database. It should match the defined in the @JoinColumn annotation of ProductRating

The default database field for the attribute id of the Product class would be product_id. However you have defined the id in AbstractEntity as name = "ID" so the @JoinColumn should be something like: @JoinColumn(name = "ID")

Upvotes: 1

Related Questions