我是 Spring 的新手,我无法弄清楚如何连接多个表以返回一些结果。我尝试实现一个小型图书馆应用程序,如下所示。
我的实体类 - 书籍、客户、预订
Book.java - 图书馆提供的书籍
@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 - 在库中注册的客户
@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 - 客户进行的所有预订
@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;
}
}
现在各个实体的表模式如下:
图书:
+------------+-------------+-----+-----+-------- +----------------+
|领域 |类型 |空 |键 |默认 |额外 |
+------------+-------------+-----+-----+-------- +----------------+
|编号 |整数(11) |否 |优先级 |空 |自动递增 |
|书名 |变种(255) |否 | |空 | |
|作者 |变种(255) |是 | |空 | |
+------------+-------------+-----+-----+-------- +----------------+
id - 主键
顾客:
+------------+-------------+-----+-----+-------- ----------+------------------+
|领域 |类型 |空 |键 |默认 |额外 |
+------------+-------------+-----+-----+-------- ----------+------------------+
|编号 |整数(11) |否 |优先级 |空 |自动递增 |
|姓名 |变种(255) |否 | |空 | |
|已注册 |日期时间 |是 | |当前_时间戳 |默认生成 |
|电话 |变种(15) |是 |大学 |空 | |
+------------+-------------+-----+-----+-------- ----------+------------------+
id - 主键
预订:
+------------+----------+-----+-----+---------- ------+--------------------+
|领域 |类型 |空 |键 |默认 |额外 |
+------------+----------+-----+-----+---------- ------+--------------------+
|编号 |整数(11) |否 |优先级 |空 |自动递增 |
| book_id |整数(11) |否 |多个 |空 | |
|客户编号 |整数(11) |否 |多个 |空 | |
|发行日期 |日期时间 |是 | |当前_时间戳 |默认生成 |
|返回日期 |日期时间 |是 | |空 | |
+------------+----------+-----+-----+---------- ------+--------------------+
id - 主键
book_id - 外键引用 books.id
customer_id - 外键引用 customer.id
现在我想做的是给出一些预订条件,如客户电话或作者姓名等,我想返回与该订单相关的所有预订。我将展示一个示例 Booking api 来解释。
预订控制器:
@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;
}
}
预订服务等级:
@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);
}
}
预订存储库类:
@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);
}
现在点击显示的预订控制器将返回一个预订对象,如下所示:
[
{
"id": 3,
"book_id": 5,
"customer_id": 2,
"issue_date": "2019-02-04 01:45:21",
"return_date": null
}
]
但我不想那样,我想与他们一起返回该预订的客户姓名以及书名。所以我希望控制器返回的预订对象看起来像这样:
[
{
"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",
}
]
有人可以帮忙做这件事吗?我被困住了,因为我无法从这里继续。
################### 编辑:我在预订类中添加了这些单向的一对一关联:
@OneToOne
@JoinColumn(name = "book_id", insertable = false, updatable = false)
private Book book;
@OneToOne
@JoinColumn(name = "customer_id", insertable = false, updatable = false)
private Customer customer;
但是现在当我点击我的控制器时,我在我的 Booking 对象中得到了整个 Book 和 Customer 对象。那么我该怎么做才能只返回预订对象中的书名和客户姓名呢?这是我的预订对象现在返回的样子:
[
{
"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
}
]
现在我的预订控制器中的 save() api 也不起作用,因为当我向它发送预订类型的对象时,bookId 和 customerId 不知何故变成了 0,这在我添加这些更改之前没有发生.
原文由 user3248186 发布,翻译遵循 CC BY-SA 4.0 许可协议
你做的是错的。您正在返回 Booking,并且您希望它神奇地反序列化为包含连接信息(如 Book Name)的实体。但是在您对存储库的选择查询中,您选择了预订。按照您的实施方式,预订不包含有关该书的信息。
首先,您需要将反序列化为 JSON 的内容与将用作 spring 数据的持久层的内容分开。
@OneToOne
/@OneToMany
从预订到预订的关系作为开始。实际上,如果您映射为 OneToOne,则默认初始化变为 EAGER,因此您的查询变得有点不合理。
如果我们假设您的映射就在持久层中,您的查询将如下所示:
这是来自 Hibernate 的映射文档> http://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#associations