我是spring新手,我不知道如何连接多个表以返回一些结果。我尝试实现一个小的库应用程序,如下所示。
我的实体类-book、customer、bookings
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;
}
}
现在,各个实体的表模式如下所示:
books:
+-----------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| book_name | varchar(255) | NO | | NULL | |
| author | varchar(255) | YES | | NULL | |
+-----------+--------------+------+-----+---------+----------------+
id - primary key
customer:
+------------+--------------+------+-----+-------------------+-------------------+
| Field | Type | Null | Key | Default | 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 - primary key
bookings:
+-------------+----------+------+-----+-------------------+-------------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+----------+------+-----+-------------------+-------------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| 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 - primary key
book_id - foreign key references books.id
customer_id - foreign key references customer.id
现在我想做的是给一些预订的关键,如客户电话或作者姓名等,我想返回所有的预订相关的订单。我将展示一个示例预订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);
}
现在点击显示的booking controller将返回如下所示的booking对象:
[
{
"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关联:
@OneToOne
@JoinColumn(name = "book_id", insertable = false, updatable = false)
private Book book;
@OneToOne
@JoinColumn(name = "customer_id", insertable = false, updatable = false)
private Customer customer;
但现在,当我点击控制器时,我的预订对象中包含了整本书和客户对象。那么我该怎么做才能在预订对象中返回bookname和customer name呢?下面是我的预订对象现在返回的样子:
[
{
"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
}
]
另外,我的booking controller中的save()api也不起作用,因为当我向它发送booking类型的对象时,bookid和customerid以某种方式显示为0,这在我添加这些更改之前是没有发生的。
3条答案
按热度按时间yhxst69z1#
您可以按照以下步骤来实现。
为响应所需的所有字段创建一个带有getter的新接口。
在@query内的查询字符串中,需要为select中的列提供名称。注意:这些名称需要与您在接口中创建的getter同步。
将此接口用作存储库方法的返回类型。
有关更多信息,可以参考spring data rest中的投影。https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#projections
5m1hhzi42#
您拥有的查询不是联接表的最佳方式。更直观的方法是这样的
b4lqfgs43#
你所做的是错误的。您正在返回booking,并希望它magicaly反序列化为一个实体,该实体包含图书名称等连接信息。但是在您对存储库的select查询中,您选择了预订。按照你的执行方式,预订并不包含关于这本书的信息。
首先,您需要将反序列化为json的内容和用作spring数据持久层的内容分开。
制造
@OneToOne
/@OneToMany
从预订到预订的关系开始。将查询更改为对已Map为book的实体/集合执行快速获取。
制作一个pojo并用json注解对其进行注解,您希望控制器返回它。
在您的持久化对象/预订与hidrated collection on book和新创建的pojo之间进行Map
实际上,如果您Map为onetoone,那么默认的初始化就变得非常迫切,因此您的查询就变得有点不必要了。
如果我们假设您的Map正好位于持久层,那么您的查询将如下所示:
这是hibernate的Map文档>http://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/hibernate_user_guide.html#associations