问题描述
我正在使用 Spring Boot 创建一个 REST API.在这个 API 中,我在 签入 和 访客 之间建立了一对多的关系.我创建了一个用于签入的控制器并使用 spring JPA 的保存功能.save 方法同时更新checkin 和guest 表,但对于guest 表,guest 表中的签入外键 没有被添加,而是显示为空.请有人帮助我.我需要同时创建访客和签到.
I am using spring boot to create a REST API. In this API, I have a One to Many relationship between check-in and Guests. I created a controller for check-in and use that save function of spring JPA.The save method is updating both checkin and guest tables but for the guest table, the check-in foreign key in the guests table is not getting added instead showing as null. Please someone help me. I need to create both guests and checkin simultaneously.
签到模型
@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");
}
}
推荐答案
使用实体类作为视图模型类可能有点棘手,特别是在这种情况下,Checkin
和 Guest
.
Using entity classes as view model classes may be a little bit tricky, especially in this case when there is a bi-directional one-to-many relation between Checkin
and Guest
.
让我们首先验证实体类和存储库是否如所描述的那样工作.为了进行测试运行,我必须为 Checkin
类中的 id 字段添加 @GeneratedValue
.
Let's start with verifying that the entity classes and repository is working as depicted. In order to make test run, I had to add @GeneratedValue
for id field in class Checkin
.
其他变化:
- 使用
Set
而不是List
.请参阅 https://stackoverflow.com/a/6563037/14072498 - 使用
@Getter
和@Setter
而不是@Data
用于实体类关系
- Use
Set
instead ofList
. See https://stackoverflow.com/a/6563037/14072498 - Use
@Getter
and@Setter
instead of@Data
for entity classes withrelations
为了验证代码,我在下面添加了一个测试类 CheckinRepositoryTest
.
I've added a test class CheckinRepositoryTest
below in order to verify the code.
如前所述,使用实体类作为视图模型类可能很棘手,因此下一步将引入两个新的视图模型类:CheckinVM
和 GuestVM
,以及一个新的服务类 GuestService
将负责保存 Checkin
和 Guest
实例.代码如下所示.
As mentioned earlier, using entity classes as view model classes can be tricky, hence next step will be to introduce two new view model classes: CheckinVM
and GuestVM
, and a new service class GuestService
that will be responsible for saving Checkin
with Guest
instances. Code is shown below.
请注意,我只为 GuestService
类添加了框架,我将它留给您来实现.CheckinRepositoryTest
中的代码指示如何实现它.
Please note that I added just the skeleton for GuestService
class, I leave it to you to implement it. Code inside CheckinRepositoryTest
indicates how to implement it.
有了视图模型类,@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
应该被删除.
With view model classes in place, @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
should be removed.
所有部分都启动并运行后,您应该向新的视图模型类添加验证,以及一些验证行为的集成测试.如果您遵循 TDD,您将在途中添加测试.
With all pieces up and running, you should add validation to your new view model classes, and some integration tests that verifies the behaviour. If you are following TDD, you'll add the tests on your way.
您还应该查看您的控制器方法,并针对成功和失败情况使用适当的状态代码.
You should also have a look at your controller method and use appropriate status codes for success and failure situations.
嘉宾班
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 类
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();
}
}
签到类
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 类
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
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();
}
}
CheckinService 类:这个交给你来实现
CheckinService class: I leave this to you to implement
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
}
}
控制器类
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 boot REST Api中的一对多关系的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!