spring 引导 REST Api 中的一对多关系
One to Many Relationship in spring boot REST Api
我正在使用 spring 启动来创建 REST API。在这个 API 中,我在 check-in 和 Guests 之间建立了一对多的关系。我创建了一个用于签入的控制器,并使用了 spring JPA 的保存功能。
保存方法正在更新 checkin 和 guest tables 但对于来宾 table,客人 table 中的签入外键未被添加,而是显示为空。请有人帮助我。我需要同时创建来宾和签到。
签到模型
@Data
@Entity
public class Checkin {
@Id
private Long id;
private Integer no_of_guests;
@OneToMany(mappedBy = "checkin", cascade = CascadeType.ALL)
private List<Guest> guests;
}
来宾模型
@Data
@Entity
public class Guest {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long guest_id;
private String name;
private String mobile_no;
private String address;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "guest_checkin_id", nullable = false )
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
private Checkin checkin;
}
签到控制器
@RestController
@RequestMapping("/checkin")
public class CheckinController {
private final CheckinRepository checkinRepo;
private final GuestRepository guestRepo;
public CheckinController(CheckinRepository checkinRepo,GuestRepository guestRepo){
this.checkinRepo = checkinRepo;
this.guestRepo = guestRepo;
}
@PostMapping("/add")
ResponseEntity<Object> roomCheckin(@RequestBody Checkin checkin){
if(checkinRepo.save(checkin) != null){
return ResponseEntity.accepted().body("Checkin Successfull");
}
return ResponseEntity.unprocessableEntity().body("Failed to Checkin");
}
}
使用实体 classes 作为视图模型 classes 可能有点棘手,尤其是在这种情况下 [=18] 之间存在双向一对多关系=] 和 Guest
.
让我们从验证实体 classes 和存储库是否如描述的那样工作开始。为了进行测试 运行,我必须在 class Checkin
.
中为 id 字段添加 @GeneratedValue
其他变化:
- 使用
Set
而不是 List
。参见
- 对实体 class 使用
@Getter
和 @Setter
而不是 @Data
关系
我在下面添加了一个测试 class CheckinRepositoryTest
以验证代码。
如前所述,使用实体 classes 作为视图模型 classes 可能很棘手,因此下一步将引入两个新的视图模型 classes:CheckinVM
和 GuestVM
,以及一个新服务 class GuestService
,它将负责保存 Checkin
和 Guest
个实例。代码如下所示。
请注意,我只添加了 GuestService
class 的框架,我将其留给您来实现。 CheckinRepositoryTest
里面的代码说明了如何实现。
有了视图模型 class,应该删除 @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
。
所有部分都已完成并 运行ning,您应该向新视图模型 classes 添加验证,以及一些验证行为的集成测试。如果您遵循 TDD,您将按自己的方式添加测试。
您还应该查看您的控制器方法,并为成功和失败情况使用适当的状态代码。
来宾class
package no.mycompany.myapp.misc;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.*;
@Getter
@Setter
@Entity
public class Guest {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long guest_id;
private String name;
private String mobile_no;
private String address;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "guest_checkin_id", nullable = false)
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
private Checkin checkin;
}
GuestVM class
package no.mycompany.myapp.misc;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
public class GuestVM {
private long id;
private String name;
private String mobile_no;
private String address;
public GuestVM(Guest guest) {
this.id = guest.getGuest_id();
this.name = guest.getName();
this.mobile_no = guest.getMobile_no();
this.address = guest.getAddress();
}
}
签到class
package no.mycompany.myapp.misc;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;
@Getter
@Setter
@Entity
public class Checkin {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Integer no_of_guests;
@OneToMany(mappedBy = "checkin", cascade = CascadeType.ALL)
private Set<Guest> guests = new HashSet<>();
}
CheckinVM class
package no.mycompany.myapp.misc;
import lombok.Getter;
import lombok.Setter;
import lombok.NoArgsConstructor;
import java.util.List;
import java.util.stream.Collectors;
@Getter
@Setter
@NoArgsConstructor
public class CheckinVM {
private long id;
private List<GuestVM> guests;
public CheckinVM(Checkin checkin) {
this.id = checkin.getId();
this.guests = checkin.getGuests().stream().map(GuestVM::new).collect(Collectors.toList());
}
}
签入存储库
package no.mycompany.myapp.misc;
import org.springframework.data.jpa.repository.JpaRepository;
public interface CheckinRepository extends JpaRepository<Checkin, Long> { }
CheckinRepositoryTest
package no.mycompany.myapp.misc;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
@DataJpaTest
public class CheckinRepositoryTest {
@Autowired
TestEntityManager testEntityManager;
@Autowired
CheckinRepository checkinRepository;
@Test
public void test() {
// create instances
var checkinInDb = new Checkin();
var guestInDb = new Guest();
// add relations
guestInDb.setCheckin(checkinInDb);
checkinInDb.getGuests().add(guestInDb);
// save check-in
checkinRepository.save(checkinInDb);
// verify that check-in has one guest
var checkin = testEntityManager.find(Checkin.class, checkinInDb.getId());
assertThat(checkin.getGuests().size()).isEqualTo(1);
// verify that guest is connected to a check-in
var guest = testEntityManager.find(Guest.class, guestInDb.getGuest_id());
assertThat(guest.getCheckin()).isNotNull();
}
}
CheckinServiceclass: 交给你去实现
package no.mycompany.myapp.misc;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class CheckinService {
private final CheckinRepository checkinRepository;
public CheckinVM saveCheckin(CheckinVM checkin) {
return null; // TODO: implement this
}
}
控制器class
package no.mycompany.myapp.misc;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/checkin")
@RequiredArgsConstructor
public class CheckinController {
private final CheckinService checkinService;
@PostMapping("/add")
ResponseEntity<Object> roomCheckin(@RequestBody CheckinVM checkin) {
if (checkinService.saveCheckin(checkin) != null) {
return ResponseEntity.accepted().body("Checkin Successful");
}
return ResponseEntity.unprocessableEntity().body("Failed to Checkin");
}
}
我正在使用 spring 启动来创建 REST API。在这个 API 中,我在 check-in 和 Guests 之间建立了一对多的关系。我创建了一个用于签入的控制器,并使用了 spring JPA 的保存功能。 保存方法正在更新 checkin 和 guest tables 但对于来宾 table,客人 table 中的签入外键未被添加,而是显示为空。请有人帮助我。我需要同时创建来宾和签到。
签到模型
@Data
@Entity
public class Checkin {
@Id
private Long id;
private Integer no_of_guests;
@OneToMany(mappedBy = "checkin", cascade = CascadeType.ALL)
private List<Guest> guests;
}
来宾模型
@Data
@Entity
public class Guest {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long guest_id;
private String name;
private String mobile_no;
private String address;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "guest_checkin_id", nullable = false )
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
private Checkin checkin;
}
签到控制器
@RestController
@RequestMapping("/checkin")
public class CheckinController {
private final CheckinRepository checkinRepo;
private final GuestRepository guestRepo;
public CheckinController(CheckinRepository checkinRepo,GuestRepository guestRepo){
this.checkinRepo = checkinRepo;
this.guestRepo = guestRepo;
}
@PostMapping("/add")
ResponseEntity<Object> roomCheckin(@RequestBody Checkin checkin){
if(checkinRepo.save(checkin) != null){
return ResponseEntity.accepted().body("Checkin Successfull");
}
return ResponseEntity.unprocessableEntity().body("Failed to Checkin");
}
}
使用实体 classes 作为视图模型 classes 可能有点棘手,尤其是在这种情况下 [=18] 之间存在双向一对多关系=] 和 Guest
.
让我们从验证实体 classes 和存储库是否如描述的那样工作开始。为了进行测试 运行,我必须在 class Checkin
.
@GeneratedValue
其他变化:
- 使用
Set
而不是List
。参见 - 对实体 class 使用
@Getter
和@Setter
而不是@Data
关系
我在下面添加了一个测试 class CheckinRepositoryTest
以验证代码。
如前所述,使用实体 classes 作为视图模型 classes 可能很棘手,因此下一步将引入两个新的视图模型 classes:CheckinVM
和 GuestVM
,以及一个新服务 class GuestService
,它将负责保存 Checkin
和 Guest
个实例。代码如下所示。
请注意,我只添加了 GuestService
class 的框架,我将其留给您来实现。 CheckinRepositoryTest
里面的代码说明了如何实现。
有了视图模型 class,应该删除 @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
。
所有部分都已完成并 运行ning,您应该向新视图模型 classes 添加验证,以及一些验证行为的集成测试。如果您遵循 TDD,您将按自己的方式添加测试。
您还应该查看您的控制器方法,并为成功和失败情况使用适当的状态代码。
来宾class
package no.mycompany.myapp.misc;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.*;
@Getter
@Setter
@Entity
public class Guest {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long guest_id;
private String name;
private String mobile_no;
private String address;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "guest_checkin_id", nullable = false)
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
private Checkin checkin;
}
GuestVM class
package no.mycompany.myapp.misc;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
public class GuestVM {
private long id;
private String name;
private String mobile_no;
private String address;
public GuestVM(Guest guest) {
this.id = guest.getGuest_id();
this.name = guest.getName();
this.mobile_no = guest.getMobile_no();
this.address = guest.getAddress();
}
}
签到class
package no.mycompany.myapp.misc;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;
@Getter
@Setter
@Entity
public class Checkin {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Integer no_of_guests;
@OneToMany(mappedBy = "checkin", cascade = CascadeType.ALL)
private Set<Guest> guests = new HashSet<>();
}
CheckinVM class
package no.mycompany.myapp.misc;
import lombok.Getter;
import lombok.Setter;
import lombok.NoArgsConstructor;
import java.util.List;
import java.util.stream.Collectors;
@Getter
@Setter
@NoArgsConstructor
public class CheckinVM {
private long id;
private List<GuestVM> guests;
public CheckinVM(Checkin checkin) {
this.id = checkin.getId();
this.guests = checkin.getGuests().stream().map(GuestVM::new).collect(Collectors.toList());
}
}
签入存储库
package no.mycompany.myapp.misc;
import org.springframework.data.jpa.repository.JpaRepository;
public interface CheckinRepository extends JpaRepository<Checkin, Long> { }
CheckinRepositoryTest
package no.mycompany.myapp.misc;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
@DataJpaTest
public class CheckinRepositoryTest {
@Autowired
TestEntityManager testEntityManager;
@Autowired
CheckinRepository checkinRepository;
@Test
public void test() {
// create instances
var checkinInDb = new Checkin();
var guestInDb = new Guest();
// add relations
guestInDb.setCheckin(checkinInDb);
checkinInDb.getGuests().add(guestInDb);
// save check-in
checkinRepository.save(checkinInDb);
// verify that check-in has one guest
var checkin = testEntityManager.find(Checkin.class, checkinInDb.getId());
assertThat(checkin.getGuests().size()).isEqualTo(1);
// verify that guest is connected to a check-in
var guest = testEntityManager.find(Guest.class, guestInDb.getGuest_id());
assertThat(guest.getCheckin()).isNotNull();
}
}
CheckinServiceclass: 交给你去实现
package no.mycompany.myapp.misc;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class CheckinService {
private final CheckinRepository checkinRepository;
public CheckinVM saveCheckin(CheckinVM checkin) {
return null; // TODO: implement this
}
}
控制器class
package no.mycompany.myapp.misc;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/checkin")
@RequiredArgsConstructor
public class CheckinController {
private final CheckinService checkinService;
@PostMapping("/add")
ResponseEntity<Object> roomCheckin(@RequestBody CheckinVM checkin) {
if (checkinService.saveCheckin(checkin) != null) {
return ResponseEntity.accepted().body("Checkin Successful");
}
return ResponseEntity.unprocessableEntity().body("Failed to Checkin");
}
}