Как сделать пружинный jpa/ правильный репозиторий при наличии обязательных отношений?

У меня есть следующая база данных, которая позволяет пользователям арендовать книги в книжном магазине:

Класс сущности Book должен иметь категорию, а также BookDescription при сохранении.

Те классы Книги выглядят так:

@Entity
@Table(name = "books")
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class Book {

@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name = "book_description_id")
private BookDescription bookDescription;

@ManyToOne(cascade = CascadeType.PERSIST, fetch = FetchType.LAZY)
private Category category;

//omitted fields, getters, setters & other relations
}

Я проверял Spring Data JPA. Имеет подпись

CrudRepository<T, ID extends Serializable>

а это значит, что у меня будет

CrudRepository<Book, String>

но как я спасу книгу?

Поэтому, как правило, пользователь отправит форму, я свяжу объект BookUIO, который будет содержать все детали, необходимые для сохранения книги, передам ее книжной ведьме, которая извлечет из нее 3 объекта: Книга (конкретная реализация), Категория и BookDescription. Вопрос заключается в том, будет ли служба подключать отношения книги и вызывать общий repository.save(Book), или он будет вызывать метод, подобный repository.save(Book, Category, BookDescription)?

Кроме того, должен ли я напрямую связать данные пользователя с классами сущностей или, как я уже сказал, связать с общим BookUIObject и позволить сервису извлечь из него классы сущностей?

С уважением,

1 ответ

Решение

Обычно вам нужно вызвать BookReporitory.save(book). В Book есть каскадный Persist для обоих отношений, поэтому, если вы установили BookDescription и Category в сохраняемом экземпляре книги, они также будут сохранены. Если у вас не было каскадного сохранения, вы должны были бы сохранить их, используя их JPARepository (если они уже не существовали в контексте постоянства).

В этом примере важно понять одну вещь: если вы создаете новый объект категории, устанавливаете его в книге и сохраняете книгу, в БД создается новая категория. Поэтому, если пользовательский интерфейс публикует категорию = sic-fi, вам нужно проверить, существует ли категория, если она есть, тогда вы должны использовать управляемую категорию и установить ее в книге, а не создавать другую категорию "научной фантастики". Это причина, по которой у меня не было бы каскадного сохранения в отношении категории, потому что я предпочел бы иметь нарушение ограничения, потому что категория не существует, а не новая категория, если кто-то пропустил, записал ее в пользовательском интерфейсе.

Я не рекомендую связывать формы напрямую с сущностями JPA, потому что вам всегда нужно извлекать сущности из JPA, так как вы должны использовать управляемые версии, поэтому по моему опыту лучше иметь другой набор компонентов для связывания форм.

Еще одна вещь, которая выскакивает, если отсутствие nullable = false в @JoinColumn. Если книга не может существовать, не находясь в категории, очень важно, чтобы это было передано в базу данных, и если вы генерируете таблицы из модели метаданных JPA, то именно так это и делается. Если бы я мог дать только одну рекомендацию при работе с базами данных /JPA, это было бы слишком усердно с NOT NULL. Получить вставленное нарушение в 100 раз проще, чем потом получить исключение NullPointerException и проверить каждый возможный путь кода, который может в итоге вызвать save, и проверить, может ли аргумент быть нулевым.

Кроме того, я бы порекомендовал вам выделить некоторое время, чтобы понять концепцию EntityManager и контекст постоянства, большинство ошибок / предположений, которые делают разработчики, возвращаются к контексту постоянства и к тому, как работают 4 состояния объекта.

Другие вопросы по тегам