4

According to this post Difference between @OneToMany and @ElementCollection? I should prefer @ElementCollection for embeddable types and @OneToMany for entities. But using @OneToMany I can additionaly set option orphanRemoval=true. How can I do this with @ElementCollection? It it implied?

k13i
  • 4,011
  • 3
  • 35
  • 63

1 Answers1

4

It is implied. Removing the owning entity would also remove all data on the @ElementCollection. Setting the Collection to null or changing elements in the Collection would cause an update if Session isn't already closed.

The official documentation here says this:

2.8.1. Collections as a value type

Value and embeddable type collections have a similar behavior as simple value types because they are automatically persisted when referenced by a persistent object and automatically deleted when unreferenced. If a collection is passed from one persistent object to another, its elements might be moved from one table to another.
...
For collections of value types, JPA 2.0 defines the @ElementCollection annotation. The lifecycle of the value-type collection is entirely controlled by its owning entity.

I ran these three tests to test it out:

  @Test
  public void selectStudentAndSetBooksCollectionToNull() {
    Student student = studentDao.getById(3L);
    List<String> books = student.getBooks();

    books.forEach(System.out::println);

    student.setBooks(null);

    em.flush(); // delete from student_book where student_id = ?
  }

  @Test
  public void selectStudentAndAddBookInCollection() {
    Student student = studentDao.getById(3L);
    List<String> books = student.getBooks();

    books.add("PHP Book");

    books.forEach(System.out::println);

    em.flush(); // insert into student_book(student_id, book) values(?, ?)
  }

  @Test
  public void selectStudentAndChangeCollection() {
    Student student = studentDao.getById(3L);
    List<String> newBooks = new ArrayList<>();

    newBooks.add("Rocket Engineering");

    newBooks.forEach(System.out::println);

    student.setBooks(newBooks);

    em.flush(); // delete from student_book where student_id = ?
    // insert into student_book(student_id, book) values(?, ?)
  } 

This is the Student class:

@Entity
@Table(name = "student")
public class Student {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name = "student_id", nullable = false, insertable = false, updatable = false)
  private Long id;

  @Column(name = "name", nullable = false)
  private String name;

  @ElementCollection
  @CollectionTable(
      name = "student_books",
      joinColumns = @JoinColumn(name = "student_id", referencedColumnName = "student_id"))
  @Column(name = "book")
  private List<String> books = new ArrayList<>();

  // Getters & Setters

}
lrkwz
  • 6,105
  • 3
  • 36
  • 59
Yoshua Nahar
  • 1,304
  • 11
  • 28
  • But that's not orphanRemoval is all about. Of course if you remove parent, children will be removed in a cascade way, but what if you just lose reference (e.g. by setting it to null) to the child, so that it's not available anymore? – k13i Sep 26 '17 at 13:24
  • 3
    Yes, the `@ElementCollection` field implicitly has `Cascasde.ALL` + `orphanRemoval = true` – Yoshua Nahar Sep 28 '17 at 17:38
  • Using Hibernate 5.0.12.Final a constraint is created with no delete cascade – lrkwz Sep 22 '22 at 09:45