如何解决在 Spring Boot 中测试 @OneToMany
我有以下实体:
@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>{
}
这里是集成测试类:
@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");
}
}
}
问题
我正在尝试测试是否可以通过 set parentId
属性正确标记子项目。我希望当设置 parentId
属性时,带有此 id
的项目应该在 subprojects
列表中包含有关子项目的信息。不幸的是,断言 assertEquals(1,foundParent.getSubprojects().size());
失败,因为列表大小为 0。我想问一下我做错了什么?我需要宣布我在春天是个新人。
解决方法
这是一个安静的常见错误。 要使其工作,您可以执行以下热修复:
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
都有对父级的引用,当父级被删除时,所有子级也被删除。
我通过以下方式修复:
类 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嵌套子项目将由服务层管理。我希望这是一个好的解决方案。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。