使用单个 DTO 对象进行投影

Using a Single DTO object for projection

我遇到了必须为每个实体对象使用单个 DTO 对象或 DTO 对象的问题。 例如我有 3 类:书籍、作者和出版商。

Book.java

@Entity
@Table(name = "tbl_book")
public class Book {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;

    @Column(name = "description")
    private String description;

    other different fields...
}

Author.java

@Entity
@Table(name = "tbl_author")
public class Book {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;

    @Column(name = "description")
    private String description;

    other different fields...
}

Publisher.java

@Entity
@Table(name = "tbl_publisher")
public class Book {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;

    @Column(name = "description")
    private String description;

    other different fields...
}

MyDTO.java

public class MyDTO {
    private Long id;
    private String description;

    constructor id, description...
    getters and setters...
}

我只想 select 使用 EntityManager 的特定字段(id 和描述):

em.createQuery("SELECT NEW MyDTO(id,description) FROM Book");

但我的问题是我应该为所有投影使用单个 DTO 对象(即 MyDTO)吗?类似于:

em.createQuery("SELECT NEW MyDTO(id,description) FROM Author");
em.createQuery("SELECT NEW MyDTO(id,description) FROM Publisher");

关于使用 DTO 进行投影的教程只是说使用 DTO 进行读取和使用实体进行写入,但他们并没有说明是否具有单个对象 DTO。您能否提供一个示例,说明为什么单个 DTO 或为什么每个实体都有 DTO。谢谢!

在我看来,为每个字段创建一个 DTO。拥有一个 DTO 会使您的对象耦合很多。例如,如果在 Book class 中您将描述更改为其他内容,您的所有代码将不再有效。

即使您一开始就为 DTO 想了一个好名字,您也会发现问题所在。 "MyDTO" 听起来不太好,也没有显示其用途,但您将无法想到一个有意义的名称。

最后但并非最不重要的一点是,单一责任原则是一件好事,用一个 DTO 来呈现多个对象会破坏它。拥有一个 class 代表不同类型的对象并不是一个好的做法,并且违反了 SOLID 原则。如果您的项目共享一些公共属性,最好使用单独的 classes 并为公共部分创建一个接口。这只是标准的 OOP 设计。它与 DTO 无关

这只是我的意见。我可能是错的。

同时创建像 JPQL 查询中那样的 DTO 使得它难以编码并且更难维护。你可以这样做:

.setResultTransformer( Transformers.aliasToBean( PostDTO.class ) ) 

您的查询或有其他方法可以做到。

我使用 DTO 已经有一段时间了,这里有一些我可以分享的东西:

  • 尝试根据您的需要构建 DTO 层次结构(抽象 类 and/or 接口)
  • 即使您的 BookDTO 'just' 扩展了一个超类(例如 AbstractIdDescriptionDTO),它总是更具可读性(IMO),并且维护起来不那么乏味,您可以' t 将一个对象误解为另一个对象
  • 我从不使用 new DTO 语法,而是实现了一个自动转换器