实体集合中的单个项目到嵌套 Dto 中

问题描述 投票:0回答:1

我有一个实体作者,它拥有一系列具有publishedDate属性的书籍。

每个作者都有一本收藏书,它们的映射如下:

public class Author {
    @Id
    private Long id;

    private String name;

    @JsonBackReference
    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "author")
    private List<Book> listBook = new ArrayList<>();

    // other fields
    // getters and setters

public class Book {

    @Id
    private Long id;

    @ManyToOne(fetch = FetchType.EAGER, optional = false)
    private Author author;    

    private LocalDateTime publishedDateTime;

我想通过 ID 获取作者,并将最新书籍作为 Dto,即

@Data
public AuthorNewestBookDto {

    Long authorId;
    String name;
   
    Book newestBook;
  1. D 到投影

将查询结果直接投射到 Dto 中。不需要映射器。高效交易 数据库。类似于这里

  1. 映射器

使用mapstruct映射器返回一个包含书籍集合的作者实体并使用@Before 注释仅返回集合中最新的一本书。类似于这里

是否有更好的方法来进行到 AuthorNewestBookDto 的转换,我需要将集合的单个最新成员检索到嵌套的单数 Dto 中。

我考虑过是否可以在休眠阶段使用 DtoResultTransformer (Hibernate 6)来完成此操作。

希望这对于 Stack Overflow 来说不是太固执己见。

java hibernate spring-data dto mapstruct
1个回答
0
投票

MapStruct 有多种工具可用于处理此类情况:

1.
Qualifier

我们可以提供实体字段类型

List<Book>
和DTO字段类型
Book
:

之间的自定义映射逻辑
interface BookingMapping {
    @Mapping(target = "newestBook", source = "listBook", qualifiedBy=NewestBookQualifier.class)
    //.. other fields
    AuthorNewestBookDto toDtoQualifiedBy(Author entity);
}
...
public class BookingMappingUtil { 
    @NewestBookQualifier
    BookDto toNewestBook(List<Book> listBook) {
        return listBook.stream()
             .max(Comparator.comparing(Book::getPublishedDateTime))
             .orElse(null)
}
...
@Qualifier
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface NewestBookQualifier{
}

可迭代到不可迭代的示例(官方 MapStruct-Example 项目)。

2.
@Named

在这种情况下,我们不需要创建新的注释。 命名注释文档

@Mapping(target = "newestBook", source = "listBook", qualifiedByName="toNewestBook" )
//.. other fields
AuthorNewestBookDto toDtoQualifiedByName(Author entity);

@Named("toNewestBook")
default BookDto toNewestBook(List<Book> listBook) {
    return listBook.stream()
             .max(Comparator.comparing(Book::getPublishedDateTime))
             .orElse(null)
}

3.
@Mapping(.. expression=".." ..)

我们能够将业务逻辑存储为字符串。这种方法可能不可读,但很容易实现。 表达式文档

@Mapping(target = "newestBook", 
          source = "listBook", 
          expression = "java( listBook.stream().max(java.util.Comparator.comparing(Book::getPublishedDateTime)).orElse(null) )" )
//.. other fields
AuthorNewestBookDto toDtoQualifiedByName(Author entity);
© www.soinside.com 2019 - 2024. All rights reserved.