Чтобы объявить связь между Taco и связанным с ним списком Ingredient-ов, аннотируйте ingredients с помощью @ManyToMany. Taco может иметь много объектов -Ingredient, и Ingredient может быть частью многих Taco.
Вы также заметили, что есть новый метод createdAt(), который аннотируется @PrePersist. Вы будете использовать его, чтобы установить свойство createdAt в текущую дату и время, прежде чем сохранить Taco. Наконец, давайте аннотируем объект Order как сущность. В следующем листинге показан новый класс Order.
Листинг 3.18 Аннотирование Order как сущность JPA
package tacos;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.OneToMany;
import javax.persistence.PrePersist;
import javax.persistence.Table;
import javax.validation.constraints.Digits;
import javax.validation.constraints.Pattern;
import org.hibernate.validator.constraints.CreditCardNumber;
import org.hibernate.validator.constraints.NotBlank;
import lombok.Data;
@Data
@Entity
@Table(name="Taco_Order")
public class Order implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private Date placedAt;
...
@ManyToMany(targetEntity=Taco.class)
private List<Taco> tacos = new ArrayList<>();
public void addDesign(Taco design) {
this.tacos.add(design);
}
@PrePersist
void placedAt() {
this.placedAt = new Date();
}
}
Как вы можете видеть, изменения Order похожи на изменения в Taco. Но есть одна новая аннотация на уровне класса: @Table. Это указывает, что сущности Order должны сохраняться в таблице с именем Taco_Order в базе данных.
Хотя вы могли бы использовать эту аннотацию на любом из объектов, это необходимо с Order. Без него JPA по умолчанию сохранит сущности в таблице с именем Order, но order является зарезервированным словом в SQL и вызовет проблемы. Теперь, когда сущности должным образом аннотированы, пришло время написать ваши репозитории.
3.2.3 Объявление репозиториев JPA
В версиях репозиториев JDBC вы явным образом объявили методы, которые должен предоставить репозиторий. Но с Spring Data вместо этого можно расширить интерфейс CrudRepository. Например, вот новый интерфейс IngredientRepository:
package tacos.data;
import org.springframework.data.repository.CrudRepository;
import tacos.Ingredient;
public interface IngredientRepository
extends CrudRepository<Ingredient, String> {
}
CrudRepository объявляет около десятка методов для операций CRUD (create, read, update, delete). Обратите внимание, что он параметризован, при этом первым параметром является тип сущности, который должен сохраняться в репозитории, а вторым параметром тип свойства entity ID. Для IngredientRepository параметрами должны быть Ingredient и String.
Аналогичным образом можно определить TacoRepository следующим образом:
package tacos.data;
import org.springframework.data.repository.CrudRepository;
import tacos.Taco;
public interface TacoRepository
extends CrudRepository<Taco, Long> {
}
Единственные существенные различия между IngredientRepositoryв и TacoRepository - это параметры CrudRepository. Здесь они установлены как Taco и Long, чтобы указать сущность Taco (и ее тип идентификатора) в качестве единицы сохранения для этого интерфейса репозитория. Наконец, те же изменения могут быть применены к OrderRepository:
package tacos.data;
import org.springframework.data.repository.CrudRepository;
import tacos.Order;
public interface OrderRepository
extends CrudRepository<Order, Long> {
}
И теперь у вас есть три репозитория. Вы можете подумать, что вам нужно написать реализации для всех трех, включая дюжину методов для каждой реализации. Но в Spring Data JPA - нет необходимости писать реализацию! При запуске приложения Spring Data JPA автоматически создает реализацию на лету. Это означает, что репозитории готовы к использованию с самого начала. Просто вставьте их в контроллеры, как вы сделали для реализаций на основе JDBC, и все готово.
Методы, предоставляемые CrudRepository обширны и отлично подходят для большинства наиболее распространенных задач. Но что, если у вас есть некоторые требования, выходящие за рамки базовой настойчивости? Давайте посмотрим как настроить репозитории для выполнения запросов, уникальных для вашего домена.
3.2.4 Настройка репозиториев JPA
Представьте, что в дополнение к основным операциям CRUD, предоставляемым CrudRepository, вам также необходимо получить все заказы, доставленные по заданному почтовому индексу. Как оказалось, это можно легко решить, добавив следующее объявление метода в OrderRepository: