Выбрать главу

Чтобы объявить связь между 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: