Переходное поле теряется при добавлении нового объекта OneToMany - PullRequest
0 голосов
/ 04 января 2019

У меня есть две сущности, которые связаны через отношение 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 никогда не вызывается. При отладке кода я вижу, что переходные поля oldId и oldIdListener устанавливаются в нулевое значение, когда метод @PostPersist вызывается для объекта shelf3, а не для shelf1 и 2.

Я думаю, это потому, что я модифицирую объект Set; но объект правильно сохраняется, он просто теряет все переходные поля. Этого не происходит, когда все дерево сохраняется впервые.

Это неправильный способ вставки нового элемента в набор OneToMany или где здесь ошибка?

Я использую Spring Boot 2.1.

Спасибо!

1 Ответ

0 голосов
/ 04 января 2019

Поле, аннотация с @Transient не будет сохраняться в базе данных, поэтому, если вы хотите, чтобы оно сохранялось, вы должны удалить @Transient.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...