[英]Test @OneToMany in Spring Boot
我有以下实体:
@Getter
@Setter
@NoArgsConstructor
@MappedSuperclass
public class BaseEntity implements Serializable{
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
public BaseEntity(Long id) {
this.id = id;
}
public boolean isNew(){
return this.id == null;
}
}
和
@Setter
@Getter
@NoArgsConstructor
@Entity
@DynamicUpdate
@Table(name = "project")
public class Project extends BaseEntity{
private static final long serialVersionUID = 1L;
@Column
@NotBlank(message = "Name property cannot be null or empty")
private String name;
@Column
private String description;
@Column
private LocalDateTime created;
@Column
private Long parentId;
@OneToMany(mappedBy = "parentId", cascade = { CascadeType.ALL }, fetch = FetchType.EAGER)
private Set<Project> subprojects = new HashSet<>();
@Builder
public Project(Long id, String name, String description, LocalDateTime created, Long parentId) {
super(id);
this.name = name;
this.description = description;
this.created = created;
this.parentId = parentId;
}
和通常的存储库:
@Repository
public interface ProjectRepository extends JpaRepository<Project, Long>{
}
这是集成测试 class:
@DataJpaTest
class ProjectRepositoryIT {
@Autowired
TestEntityManager testEntityManager;
@Autowired
ProjectRepository projectRepository;
@Test
@Transactional
void testSaveSubproject() {
Project parent = Project.builder().name("parent").build();
parent = testEntityManager.persistAndFlush(parent);
Project child = Project.builder().name("child").parentId(parent.getId()).build();
child = testEntityManager.persistAndFlush(child);
var optionalParent = projectRepository.findById(parent.getId());
if(optionalParent.isPresent()) {
var foundParent = optionalParent.get();
assertEquals(parent.getId(), foundParent.getId());
assertEquals(1, foundParent.getSubprojects().size());
Optional<Project> matchigProject = foundParent.getSubprojects()
.stream()
.filter(p -> p.getId().equals(foundParent.getId()))
.findFirst();
assertTrue(matchigProject.isPresent());
assertEquals(child.getId(), matchigProject.get().getId());
}else {
fail("cannot find parent project");
}
}
}
问题
我正在尝试测试是否可以通过设置parentId
属性正确标记子项目。 我希望在设置parentId
属性时,具有此id
的项目应该在subprojects
列表中包含有关子项目的信息。 不幸的是断言assertEquals(1, foundParent.getSubprojects().size());
失败,因为列表大小为 0。我想请教我做错了什么? 我需要宣布我是 Spring 的新手。
这是一个安静的常见错误。 要使其正常工作,您可以执行以下热修复:
Project parent = Project.builder().name("parent").build();
Project child = Project.builder().name("child").build();
parent.getSubprojects().add(child);
parent = testEntityManager.persistAndFlush(parent);
child.setParentId(parent.getId());
child = testEntityManager.persistAndFlush(child);
Spring 不会自动将子实体中的 parentId 与父实体中的子项目集绑定,没有魔法。 您必须将子实体放在父实体的子项目集中保存它,然后自己设置子实体的 parentId 并仔细管理。
感谢@Alex Crazy 的回答。 我的目标是让它尽可能简单。 我希望每个Project
都有对父级的引用,当父级被删除时,所有子级也被删除。
我通过以下方式修复:
Class Project
只有parentId
字段,没有任何@OneToMany
或@ManyToOne
链接:
...
public class Project extends BaseEntity{
...
@Column
private Long parentId;
...
}
然后通过以下搜索扩展ProjectRepository
:
@Repository
public interface ProjectRepository extends JpaRepository<Project, Long>{
List<Project> findAllByParentId(Long id);
void deleteAllByParentId(Long id);
}
和测试:
@Test
void testFindSubprojects() {
// Prepare database
Project parent = Project.builder().name("parent").build();
parent = testEntityManager.persistAndFlush(parent);
Project child = Project.builder().name("child").parentId(parent.getId()).build();
child = testEntityManager.persistAndFlush(child);
// Call repository
Project foundParent = projectRepository.findById(parent.getId()).orElseThrow(() -> fail());
assertNotNull(foundParent.getId());
List<Project> subprojects = projectRepository.findAllByParentId(foundParent.getId());
assertEquals(1, subprojects.size());
assertEquals(child.getId(), subprojects.get(0).getId());
assertEquals(child.getParentId(), foundParent.getId());
}
@Test
void testDeleteAllByParentId() {
// Prepare database
Project parent = Project.builder().name("parent").build();
parent = testEntityManager.persistAndFlush(parent);
testEntityManager.persistAndFlush(Project.builder().name("child1").parentId(parent.getId()).build());
testEntityManager.persistAndFlush(Project.builder().name("child2").parentId(parent.getId()).build());
testEntityManager.persistAndFlush(Project.builder().name("child3").parentId(parent.getId()).build());
var subprojects = projectRepository.findAllByParentId(parent.getId());
assertEquals(3, subprojects.size());
projectRepository.deleteAllByParentId(parent.getParentId());
subprojects = projectRepository.findAllByParentId(parent.getParentId());
assertEquals(0, subprojects.size());
}
删除 ass 嵌套子项目将由服务层管理。 我希望这是一个很好的解决方案。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.