Hi! I am trying to debug an issue in my application but I can’t really get my head around it. I have the following two entities:
import jakarta.persistence.*;
import lombok.*;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import org.hibernate.annotations.Where;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
@Entity
@Table(name = "BOOK")
@EqualsAndHashCode(of = { "id" })
@ToString(of = { "id" })
@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Book implements Serializable {
@Id
@SequenceGenerator(name = "BOOK_SEQ", sequenceName = "BOOK_SEQ", allocationSize = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "BOOK_SEQ")
@Column(name = "BOOK_ID", columnDefinition = "NUMBER(38,0)")
private Long id;
@Builder.Default
@OneToMany(mappedBy = "book", fetch = FetchType.LAZY, orphanRemoval = true, cascade = { CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH, CascadeType.DETACH })
@Fetch(FetchMode.SUBSELECT)
@Where(clause = "AGE < 60")
private Set<Author> authors = new HashSet<>();
@Column(name = "TITLE", columnDefinition = "VARCHAR2(50 CHAR)")
private String title;
public Integer getAuthorAmount() {
return authors.size();
}
}
and
import jakarta.persistence.*;
import lombok.*;
import org.hibernate.annotations.Where;
import java.io.Serializable;
@Entity
@Table(name = "AUTHOR")
@EqualsAndHashCode(of = { "id" })
@ToString(of = { "id" })
@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Where(clause = "AGE < 60")
public class Author implements Serializable {
@Id
@SequenceGenerator(name = "AUTHOR_SEQ", sequenceName = "AUTHOR_SEQ", allocationSize = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "AUTHOR_SEQ")
@Column(name = "AUTHOR_ID", columnDefinition = "NUMBER(38,0)")
private Long id;
@ManyToOne(optional = false, fetch = FetchType.LAZY)
@JoinColumn(name = "BOOK_ID", columnDefinition = "NUMBER(38,0)")
private Book book;
@Column(name = "NAME", columnDefinition = "VARCHAR2(50 CHAR)")
private String name;
@Column(name = "age", columnDefinition = "NUMBER(3,0)")
private Integer age;
}
and the following in my BookController.java:
private Book selectedBook;
@PostMapping("/increaseAge")
@Transactional
public String increaseAge() {
selectedBook.getAuthors().forEach(author -> author.setAge(70));
selectedBook = bookRepository.save(selectedBook);
return "redirect:/book";
}
@PostMapping("/save")
@Transactional
public String saveEntity() {
selectedBook = bookRepository.save(selectedBook);
return "redirect:/book";
}
When pressing the button in my GUI that calls the increaseAge() method, the following queries are ran:
Hibernate: select b1_0.book_id,a1_0.book_id,a1_0.author_id,a1_0.age,a1_0.name,b1_0.title from book b1_0 left join author a1_0 on b1_0.book_id=a1_0.book_id and (( a1_0.AGE < 60 ) and ( a1_0.AGE < 60 )) and (( a1_0.AGE < 60 ) and ( a1_0.AGE < 60 )) where b1_0.book_id=?
Hibernate: update author set age=?,book_id=?,name=? where author_id=?
Hibernate: update author set age=?,book_id=?,name=? where author_id=?
Which looks good, note that selectedBooks.getAuthors() still has all authors until I do a page refresh or load the entity from a new session (which I want to avoid, but it is fine if they are still loaded in the entity, I just want to avoid the upcoming issue).
Now my issue appears, if I increase the age of all authors so that the clause of my @Where annotation goes from true to false, then I edit something with my book and hit the save button, I get the following queries:
Hibernate: select b1_0.book_id,a1_0.book_id,a1_0.author_id,a1_0.age,a1_0.name,b1_0.title from book b1_0 left join author a1_0 on b1_0.book_id=a1_0.book_id and (( a1_0.AGE < 60 ) and ( a1_0.AGE < 60 )) and (( a1_0.AGE < 60 ) and ( a1_0.AGE < 60 )) where b1_0.book_id=?
Hibernate: select a1_0.author_id,a1_0.age,a1_0.book_id,a1_0.name from author a1_0 where a1_0.author_id=? and (a1_0.AGE < 60)
Hibernate: select author_seq.nextval from dual
Hibernate: select a1_0.author_id,a1_0.age,a1_0.book_id,a1_0.name from author a1_0 where a1_0.author_id=? and (a1_0.AGE < 60)
Hibernate: select author_seq.nextval from dual
Hibernate: insert into author (age,book_id,name,author_id) values (?,?,?,?)
Hibernate: insert into author (age,book_id,name,author_id) values (?,?,?,?)
It looks like the Authors which @Where clause has gone from true to false gets inserted into the database again with an incremented ID:
Is there something wrong with my setup or the way I am saving? Currently I am testing with 6.2.7.Final but have the same issue back in 5.0.12.Final as well.
Note: This is just a mockup of an issue in my application so don’t look too much into the logistics between the Book and Author