将Spring Data JPA Page内容的类型转换

40

我正在使用Spring Data JPA,并且拥有一个PagingAndSortingRepository<Contact, Long>,它使用了JPASpecificationExecutor<Contact>。 我将一个Specification和一个Pageable实例传递给该存储库的.findAll()方法,以获取一个Page<Contact>

然而,我的Contact实体有很多额外的字段和映射,在前端上我并不需要。因此,我有一个ContactDto,其中只包含必要的字段,并且我有一个方法可以将Contact转换为ContactDto

private ContactDto convertToContactDto(Contact contact) {
    //do the conversion
}

我该如何使用这种转换方法将 Page<Contact> 转换为 Page<ContactDto>

我可以获取 Page<Contact> 的内容,并执行以下转换。

final Page<Contact> contactPage = pagingAndSortingContactRepository
        .findAll(ContactSpecification.findByFirstNmLike(firstNm), pageable);

final Collection<ContactDto> contactDtos = contactPage.getContent()
    .stream()
    .map(this::convertToContactDto)
    .collect(Collectors.toList());

但是我现在只有一个Collection而不是一个Page,我不知道如何将这个Collection添加到Page的内容中。有什么方法可以做到这一点吗?或者有没有另一种方式可以在Page<Contact>实例本身上调用转换方法?

2个回答

94

原来 Page 有自己的 .map() 方法,你可以将一个方法引用传递给它来进行转换。

以下是我最终完成转换的方法。

final Page<ContactDto> contactDtoPage = contactPage.map(this::convertToContactDto);

convertToContactDto 方法只是创建并返回我试图转换成的类的实例:

private ContactDto convertToContactDto(final Contact contact) {
    final ContactDto contactDto = new ContactDto();
    //get values from contact entity and set them in contactDto
    //e.g. contactDto.setContactId(contact.getContactId());
    return contactDto;
}

这个方法很管用。比起创建一个新的页面实例并复制对象,它要简单得多。 - Krishna Vedula
@Andrew,你能否包含一些从convertToContactDto函数中的代码示例吗? - Al Grant
非常有用 - 使用PagingAndSortingRepository比使用投影要容易得多。 - simbro
我一开始就是这样做的,但对我来说行不通。现在我看到了这个解决方案,每个人都很高兴。我有一个奇怪的java.lang.ClassCastException。 类[Ljava.lang.Object;无法转换为类***.model.Schedule([Ljava.lang.Object;在加载器“引导程序”的java.base模块中;***l.Schedule在加载器“应用程序”的未命名模块中)。这是什么鬼? - matua

6

可能情况是,逐个执行页面转换的效率比整个集合一次性处理要低,因为Page.map(..)很可能会这样做。

在这种情况下,我们可以使用Spring的PageExecutionUtils来完成重新构建带有转换内容的页面的繁琐工作。

public Page<TypeB> getPageAsTypeB(Pageable pageable) {
    Page<TypeA> pageA = pagingAndSortingContactRepository(pageable);
    Function<List<TypeA>, List<TypeB>> collectionTransform;

    Page<TypeB> pageB = PageableExecutionUtils.getPage(
        collectionTransform.apply(pageA.getContent()),
        pageable,
        pageA::getTotalElements);
    return pageB;
}

从你的回答中不清楚你是从哪里得到“可分页”的信息... - James Gawron
我更新了示例代码,以展示所讨论的“pageable”是如何在仓库查询中使用的,从而生成了预转换的“pageA”。 - spaceman spiff
Function<List<TypeA>, List<TypeB>> collectionTransform; 这是什么?它对我不起作用,因为它需要初始化。请详细说明。 - matua
@matua,假设您有能力定义“List”转换“Function”、“collectionTransform”。请记住,这种特定方法的重点是利用当您手头有一组对象时更有效的转换,而不是逐个执行。如果您无法定义以这种方式更高效的函数,则没有使用它的理由! - spaceman spiff

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接