在spring boot中测试@onetomany

voj3qocg  于 2021-06-29  发布在  Java
关注(0)|答案(2)|浏览(494)

我有以下实体:

@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 列表。不幸的Assert assertEquals(1, foundParent.getSubprojects().size()); 失败,因为列表大小为0。我想请教一下我做错了什么?我要宣布我在Spring是新来的。

j9per5c4

j9per5c41#

这是一个很常见的错误。要使其正常工作,您可以执行以下热修复程序:

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并小心地管理它。

vi4fp9gy

vi4fp9gy2#

谢谢你的回答。我的目标是使它尽可能简单。我每天都要 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());
    }

删除嵌套子项目将由服务层管理。我希望这是个好办法。

相关问题