Je suis nouveau dans Spring et je n'arrive pas à comprendre comment joindre plusieurs tables pour renvoyer un résultat. J'ai essayé d'implémenter une petite application de bibliothèque comme indiqué ci-dessous.
Mes classes d'entités - Livre, client, réservations
Book.Java - livres disponibles dans la bibliothèque
@Entity
@Table(name = "books")
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", columnDefinition = "int")
private int id;
@NotNull(message = "Book name cannot be null")
@Column(name = "book_name", columnDefinition = "VARCHAR(255)")
private String bookName;
@Column(name = "author", columnDefinition = "VARCHAR(255)")
private String author;
// getters and setters
public Book() {}
public Book(String bookName, String author) {
this.bookName = bookName;
this.author = author;
}
}
Customer.Java - Clients enregistrés dans la bibliothèque
@Entity
@Table(name = "customer", uniqueConstraints = {@UniqueConstraint(columnNames = {"phone"})})
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", columnDefinition = "int")
private int id;
@NotNull(message = "Customer name cannot be null")
@Column(name = "name", columnDefinition = "VARCHAR(255)")
private String name;
@Column(name = "phone", columnDefinition = "VARCHAR(15)")
private String phone;
@Column(name = "registered", columnDefinition = "DATETIME")
private String registered;
// getters and setters
public Customer() {}
public Customer(String name, String phone, String registered) {
this.name = name;
this.phone = phone;
this.registered = registered;
}
}
Booking.Java - Toutes les réservations effectuées par les clients
@Entity
@Table(name = "bookings")
public class Booking {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", columnDefinition = "int")
private int id;
@NotNull(message = "Book id cannot be null")
@Column(name = "book_id", columnDefinition = "int")
private int bookId;
@NotNull(message = "Customer id cannot be null")
@Column(name = "customer_id", columnDefinition = "int")
private int customerId;
@Column(name = "issue_date", columnDefinition = "DATETIME")
private String issueDate;
@Column(name = "return_date", columnDefinition = "DATETIME")
private String returnDate;
// getters and setters
public Booking() {}
public Booking(int bookId, int customerId, String issueDate) {
this.bookId = bookId;
this.customerId = customerId;
this.issueDate = issueDate;
}
}
Maintenant, les schémas de table pour les entités respectives sont les suivants:
livres: + ----------- + -------------- + ------ + --- - + --------- + ---------------- + | Champ | Type | Null | Clé | Par défaut | Extra | + ----------- + -------------- + ------ + ----- + - ------- + ---------------- + | id | int (11) | NON | PRI | NULL | incrémentation automatique | | Nom_livre | varchar (255) | NON | | NULL | | | Auteur | varchar (255) | OUI | | NULL | | + ----------- + -------------- + ------ + ----- + - -------- + ---------------- + id - clé primaire client: + ------------ + -------------- + ------ + ----- + ------ ------------- + ------------------- + | Champ | Type | Null | Clé | Par défaut | Extra | + ------------ + -------------- + ------ + ----- + - ------------------ + ------------------- + | id | int (11 ) | NO | PRI | NULL | auto_increment | | Name | varchar (255) | NO | | NULL | | | Registered | datetime | YES | | CURRENT_TIMESTAMP | DEFAULT_GENERATED | | Phone | varchar (15) | YES | UNI | NULL | | + ------------ + ------ -------- + ------ + ----- + ------------------- + ------------------- + id - clé primaire réservations: + ------------- + ---------- + - ----- + ----- + ------------------- + ------------------ - + | Champ | Type | Null | Clé | Par défaut | Extra | + ------------- + ---------- + ------ + ----- + ---- --------------- + ------------------- + | id | int (11) | NON | PRI | NULL | incrémentation automatique | | Book_id | int (11) | NO | MUL | NULL | | | Customer_id | int (11) | NO | MUL | NULL | | | Issue_date | datetime | YES | | CURRENT_TIMESTAMP | DEFAULT_GENERATED | | Return_date | datetime | YES | | NULL | | + ------ ------- + ---------- + ------ + ----- + ------------------ - + ------------------- + id - clé primaire book_id - clé étrangère référence books.id customer_id - la clé étrangère fait référence à customer.id
Maintenant, ce que je veux faire, c'est donner des critiques de réservation comme le téléphone du client ou le nom de l'auteur, etc., je veux retourner toutes les réservations liées à cette commande. Je vais vous montrer un exemple d'API de réservation pour expliquer.
Contrôleur de réservation:
@RestController
@RequestMapping("/bookings")
public class BookingController {
@Autowired
BookingService bookingService;
// some booking apis which return Booking objects
@GetMapping
public List<Booking> getAllBookingsBy(@RequestParam("phone") String phone,
@RequestParam("authors") List<String> authors) {
return bookingService.getAllBy(phone, authors);
}
@PostMapping
public Booking addBooking(@RequestBody Booking booking) {
bookingService.saveBooking(booking);
return booking;
}
}
Classe de service de réservation:
@Service
public class BookingService {
@Autowired
private BookingRepository bookingRepository;
// some booking service methods
// get all bookings booked by a customer with matching phone number and books written by a given list of authors
public List<Booking> getAllBy(String phone, List<String> authors) {
return bookingRepository.queryBy(phone, authors);
}
public void saveBooking(Booking booking) {
bookingRepository.save(booking);
}
}
Classe de référentiel de réservation:
@Repository
public interface BookingRepository extends JpaRepository<Booking, Integer> {
// some booking repository methods
@Query(value = "SELECT * FROM bookings bs WHERE " +
"EXISTS (SELECT 1 FROM customer c WHERE bs.customer_id = c.id AND c.phone = :phone) " +
"AND EXISTS (SELECT 1 FROM books b WHERE b.id = bs.book_id AND b.author IN :authors)",
nativeQuery = true)
List<Booking> queryBy(@Param("phone") String phone,
@Param("authors") List<String> authors);
}
Maintenant, frapper le contrôleur de réservation affiché retournera un objet de réservation qui ressemble à ceci:
[
{
"id": 3,
"book_id": 5,
"customer_id": 2,
"issue_date": "2019-02-04 01:45:21",
"return_date": null
}
]
Mais je ne le veux pas comme ça, je veux retourner avec eux le nom du client pour cette réservation et aussi le nom du livre. Je veux donc que les objets de réservation retournés par le contrôleur ressemblent à ceci:
[
{
"id": 3,
"book_id": 5,
"customer_id": 2,
"issue_date": "2019-02-04 01:45:21",
"return_date": null,
"customer_name": "Cust 2",
"book_name": "Book_2_2",
}
]
Quelqu'un peut-il m'aider à le faire? Je suis bloqué car je ne peux pas continuer à partir d'ici.
EDIT: J'ai ajouté ces associations unidirectionnelles individuelles dans ma classe de réservation:
@OneToOne
@JoinColumn(name = "book_id", insertable = false, updatable = false)
private Book book;
@OneToOne
@JoinColumn(name = "customer_id", insertable = false, updatable = false)
private Customer customer;
Mais maintenant, lorsque j'appuie sur mon contrôleur, j'obtiens tous les objets Livre et Client dans mon objet Réservation. Alors, que puis-je faire pour renvoyer simplement le nom du livre et le nom du client dans l'objet de réservation? Voici à quoi ressemble mon objet Booking retourné:
[
{
"id": 3,
"book_id": 5,
"book": {
"id": 5,
"book_name": "Book_2_2",
"author": "author_2"
},
"customer_id": 2,
"customer": {
"id": 2,
"name": "Cust 2",
"phone": "98765431",
"registered": "2019-02-04 01:13:16"
},
"issue_date": "2019-02-04 01:45:21",
"return_date": null
}
]
De plus, maintenant mon API save () dans mon contrôleur de réservation ne fonctionne pas parce que lorsque j'y envoie un objet de type Booking, bookId et customerId deviennent en quelque sorte 0, ce qui ne s'est pas produit avant d'ajouter ces modifications .
La requête que vous avez n'est pas la meilleure façon de joindre des tables. Une manière plus intuitive est comme ça
SELECT * FROM bookings
WHERE customer_id in (SELECT id FROM customer WHERE phone = :phone)
AND book_id in (SELECT id FROM books WHERE author IN :authors)
Vous pouvez l'implémenter selon les étapes ci-dessous.
Pour plus d'informations, vous pouvez consulter Projections dans le repos de données du printemps. https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#projections