我有两个通过OneToMany关系链接的实体:
@Entity
@Table(name="bookcase")
public class BookCase {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Transient
@Getter @Setter private Long oldId;
/*
https://vladmihalcea.com/a-beginners-guide-to-jpa-and-hibernate-cascade-types/
*/
@OneToMany(mappedBy = "bookCase", cascade = CascadeType.ALL, orphanRemoval = true)
private Set<Bookshelf> bookShelves = new HashSet<>();
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public Set<Bookshelf> getBookShelves() { return bookShelves; }
public void setBookShelves(Set<Bookshelf> bookShelves) { this.bookShelves = bookShelves; }
}
@Entity
@Table(name="bookshelf")
public class Bookshelf {
private static final Logger log = LoggerFactory.getLogger(Bookshelf.class);
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Transient
@Getter @Setter private Long oldId;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "bookcase_id")
private BookCase bookCase;
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public BookCase getBookCase() { return bookCase; }
public void setBookCase(BookCase bookCase) {
this.bookCase = bookCase;
bookCase.getBookShelves().add(this);
}
@Transient
@Setter private OldIdListener oldIdListener;
/*
When the id is saved, listening DTOs can update their ids
*/
@PostPersist
public void triggerOldId() {
log.info("Postpersist triggered for {}", id);
if (oldIdListener != null) {
oldIdListener.updateId(oldId, id);
}
}
}
public interface OldIdListener {
void updateId(long oldId, long newId);
}
以下测试失败:
@Test
public void testThatCascadingListenerIsTriggered() {
var mock = mock(OldIdListener.class);
var mock2 = mock(OldIdListener.class);
var mock3 = mock(OldIdListener.class);
var bookcase = new BookCase();
var shelf1 = new Bookshelf();
shelf1.setOldId(-5L);
shelf1.setBookCase(bookcase);
shelf1.setOldIdListener(mock);
var shelf2 = new Bookshelf();
shelf2.setOldId(-6L);
shelf2.setBookCase(bookcase);
shelf2.setOldIdListener(mock2);
var saved = bookCaseRepository.save(bookcase);
verify(mock).updateId(eq(-5L), anyLong());
verify(mock2).updateId(eq(-6L), anyLong());
var savedBookCase = bookCaseRepository.findById(saved.getId()).get();
assertThat(savedBookCase.getBookShelves()).hasSize(2);
var shelf3 = new Bookshelf();
shelf3.setOldId(-10L);
shelf3.setBookCase(savedBookCase);
shelf3.setOldIdListener(mock3);
savedBookCase.getBookShelves().add(shelf3);
bookCaseRepository.save(savedBookCase);
verify(mock3).updateId(eq(-10L), anyLong());
}
mock3永远不会被调用。
在调试代码时,我看到在对象架子3而非架子1和2上调用oldId
方法时,瞬变字段oldIdListener
和@PostPersist
设置为null。
我认为这是因为我正在修改Set对象;但是该对象已正确保留,只会丢失所有瞬态字段。第一次保留整个树时,不会发生这种情况。
将新元素插入到OneToMany集中是错误的方法吗?还是这里的错误在哪里?
我正在使用Spring Boot 2.1。
谢谢!
答案 0 :(得分:0)
使用@Transient注释的字段将不会保留在数据库中,因此,如果要保留它,则必须删除@Transient。