В нашем проекте мы используем jpa данных spring с спящим режимом.
Ниже приведен пример представления сущностей.
@Entity
public class Author {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long authorId;
private String firstName;
@OneToOne(mappedBy = "author")
private Book book;
...
}
@Entity
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String title;
@OneToOne(fetch= FetchType.LAZY)
private Author author;
...
}
Пожалуйста, простите любые проблемы с синтаксисом.
У нас есть только поле ассоциации OneToOne для автора в объекте книги. Это имеет много недостатков для нашего дизайна.
authorId в таблице книг в качестве внешнего ключа.authorId для уникальной идентификации записи только из-за ленивых ассоциаций гибернации, в равном и контракте хэш-кода, даже если мы хотим его использовать. Если мы используем ассоциацию автора в равных и хэш-коде, он будет охотно вызывать сущность автора для каждой книги, которая нам не нужна.book.author.authorId использовался в слишком многих местах, и это требовало дополнительного соединения или запроса таблицы авторов только для того, чтобы получить только идентификатор.Чтобы решить эту проблему, мы создали еще одно поле authorId в объекте Book.
book.authorId во всех запросах, не извлекая сущность автора.insertable и updateable ложными, как упоминалось на многих форумах, чтобы один столбец отображался на несколько полей.@Entity
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String title;
@OneToOne
private Author author;
@Column(name = "authorId", insertable = false,updatable = false)
private Long authorId
...
}
Я тестировал следующее до сих пор:
Вопросы:
Author author = repository.findById();
Book b = new Book();
b.setAuthor(author)
b.setAuthorId(author.getId)
также любой другой случай, когда мне явно нужно установить book.authorId ? Будет ли он правильно управляться с помощью спящего режима?
Согласен с @fnymmm - почему автор должен быть привязан ровно к одной книге? Лучше использовать отношение «один ко многим».
прежде всего уточните свою функциональную потребность, вы действительно хотите, чтобы у автора было ровно 0 или 1 книга? потому что это то, что мы видим из предоставленного вами кода
Будет ровно 1 книга. @fnymmm и Арно, как я уже сказал в посте, сущности - это просто имитация реального сценария.




- Насколько я понял, это поле предназначено только для чтения и установлено для меня спящим режимом, я никогда не должен явно нигде обновлять это поле, правильно ли я понимаю?
Да, как только одно и то же поле используется для ассоциации, вы не можете его трогать. Если вам нужно обновить значение в БД, вы должны сделать это через обновление Book.author. В своей сущности просто создайте частный сеттер в своей сущности Booke, чтобы убедиться, что поле не будет затронуто.
- Можем ли мы безопасно использовать authorId, представленный как новое поле в запросах hql/jpql и sql
Вы можете, но, вероятно, не должны. В своем вопросе выше вы написали:
Здесь у нас ранее был контрольно-пропускной пункт, так как book.author.authorId использовался в слишком многих местах, и это требовало дополнительного объединения или запроса таблицы авторов только для того, чтобы получить только идентификатор.
Если вы посмотрите на сгенерированный код, вы обнаружите, что не сгенерировано предложение join, поскольку Hibernate достаточно умен, чтобы брать значение из столбца author_id таблицы Books. т. е. если вы пишете JPQL-запрос типа
select book from Book book where book.author.auhtorId = :authorId
результирующий запрос будет
select b.* from books b where b.author_id = ?`
- Будет ли это поле корректно управляться спящим режимом?
Да, Hibernate в основном полагается на отражение, поэтому даже с закрытыми методами доступа код правильный.
- Нам нужно установить это явно?
Нет, вам не нужно этого делать. Вам нужно заботиться о Book.author, потому что это связанная сущность. Как только Book.authorId аннотируется @Column(name = "authorId", insertable = false,updatable = false) Hibernate ожидает, что вы не будете его обновлять, с точки зрения вашего кода этого достаточно:
Author author = repository.findById();
Book b = new Book();
b.setAuthor(author)
P.S. В приведенном выше фрагменте вместо Author author = repository.findById(); вы можете использовать Author author = repository.getById(); сохранение одного вызова БД, поскольку JpaRepository.getById() возвращает прокси с id вместо фактического извлечения данных.
Вы пробовали изменить поле
BookinAuthorнаList<Book>. Таким образом, должно работать сопоставление один ко многим.