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

oxiaedzo  于 2023-10-23  发布在  其他
关注(0)|答案(1)|浏览(105)

我有一个实体Author,它有一个Books集合,该集合的属性为ExclusiveshedDate。
每个作者都有一本书,它们被Map成这样:

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;

我想得到一个作者的身份证与最新的书作为一个DTO,即。

@Data
public AuthorNewestBookDto {

    Long authorId;
    String name;
   
    Book newestBook;
  1. DtoProjection
    将查询结果直接转换到Dto中。不需要Map器。数据库上的高效事务。类似于here
    1.Map器
    使用mapstructMap器返回一个包含书籍集合的Author实体,并使用@Before注解仅返回集合中最新的一本书。类似于here
    有没有更好的方法来转换到AuthorNewestBookDto,在这里我需要检索一个集合的单个最新成员到一个嵌套的单个Dto中。
    我已经考虑过是否可以在休眠阶段使用DtoResultTransformer(Hibernate 6)。
    希望这对Stack Overflow来说不是太自以为是。
fxnxkyjh

fxnxkyjh1#

MapStruct有多种工具可用于这种情况:

1. Qualifier

我们可以提供Entity字段类型之间的自定义Map逻辑: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{
}

Iterable to non-iterable example(官方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=".." ..)

我们可以将业务逻辑存储为String。这种方法可能不是可读的,但很容易实现。表达式文档

@Mapping(target = "newestBook", 
          source = "listBook", 
          expression = "java( listBook.stream().max(java.util.Comparator.comparing(Book::getPublishedDateTime)).orElse(null) )" )
//.. other fields
AuthorNewestBookDto toDtoQualifiedByName(Author entity);

相关问题