CQRS中JPA实体与DTO之间的映射

时间:2015-03-15 13:54:35

标签: java jpa cqrs data-transfer-objects

我希望在我正在开发的项目中使用CQRS,但是我目前正在努力实现CQRS的查询方面的最佳方法。基于我有限的理解,有一个瘦数据层(有时称为精简读取层),它查询数据库并返回一个DTO,其中包含应用程序UI层使用的查询结果。

由于这是一个Java EE应用程序,我正在开发瘦数据层使用JPA使用EntityManager.createNamedQuery查询数据库,该@Entity @Table(name = "ORDER") public class Order { // Various named queries @Id @Column(name = "ORDER_ID") private UUID orderId; @Column(name = "ORDER_NUMBER") private long orderNumber; @Column(name = "ORDER_DATE") @Temporal(TemporalType.DATE) private Date orderDate; @Column(name = "CUSTOMER_NAME") private String customerName; @OneToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE }, orphanRemoval=true) @JoinColumn(name = "ORDER_NUMBER", referencedColumnName = "ORDER_NUMBER") private List<OrderLine> orderLines; // Getters and setters, equals, hashCode, toString } @Entity @Table(name = "ORDER_LINE") public class OrderLine { @Id @Column(name = "ORDER_LINE_ID") private UUID orderLineId; @OneToOne(fetch=FetchType.EAGER) @JoinColumn(name = "ORDER_ID", referencedColumnName = "ORDER_ID") private Order order; @Column(name = "PART_NUMBER") private String partNumber; @Column(name = "DESCRIPTION") private String description; @Column(name = "UNIT_PRICE") private BigDecimal unitPrice; @Column(name = "QUANTITY") private int quantity; // Getters and setters, equals, hashCode, toString } public class OrderDTO { private long orderNumber; private Date orderDate; private String customerName; private List<OrderLine> orderLines; public OrderDTO() {} public OrderDTO(long orderNumber, Date orderDate, String customerName, List<OrderLineDTO> orderLines) { this.orderNumber = orderNumber; this.orderDate = orderDate; this.customerName = customerName; this.orderLines = orderLines; } //Getters but no setters } public class OrderLineDTO { private String partNumber; private String description; private BigDecimal unitPrice; private int quantity; public OrderLineDTO() {} public OrderLineDTO(String partNumber, String description, BigDecimal unitPrice, int quantity) { this.partNumber = partNumber; this.description = description; this.unitPrice = unitPrice; this.quantity = quantity; } //Getters but no setters } 返回一个包含结果的实体,然后我将其映射到DTO。

鉴于应用程序的查询端应该是“只读”,DTO包含getter但不包含每个属性的setter,以及用于在创建时填充属性的构造函数。

对于一个简单的查询,我可以使用构造函数手动将实体中的值映射到DTO,但是这对于更复杂的查询是不实际的,特别是在实体包含需要的“一对多”关系的情况下映射到相应的DTO。我已经看过使用Dozer和ModelMapper之类的映射框架,但是它们似乎都依赖于具有setter的DTO,并且似乎没有使用构造函数。

以下代码代表了我创建的两个实体和两个DTO的非常简化的视图,以帮助解释这种情况。

{{1}}

我的问题是:

  1. 使用CQRS时,DTO应该只有getter和构造函数 或者也可以设置制定者?

  2. 如果理想情况下DTO应该只有getter和构造函数,那么是 映射框架填充实体所在DTO的最佳方法 返回一个包含“一对多”的复杂结果集 关系

  3. 是否有任何可以使用构造函数的映射框架 比定居者?

1 个答案:

答案 0 :(得分:2)

  1. 最好的方法是只有getter和构造函数。然后你的DTO是不变的。
  2. 您可以通过两种方式制作DTO。一种是使用JPA和select new my_package.MyDto(u.username, u.email) from User u之类的查询。对于包括许多表结果的更大dtos更受欢迎的第二个是使用非jpa技术,如MyBatis或SpringJdbcTemplate。第二种方式更有意义,因为您没有从数据库中检索不必要的数据。因此,由于性能原因,您应该只获得创建DTO所需的数据。
  3. 是 - 例如,最受欢迎的JacksonMapper可以使用构造函数而不是setter。像Orika这样的其他框架也可以创建这样的映射。您可以在我的博文http://www.kubrynski.com/2015/02/datatransferobject-myth-busting.html
  4. 上找到详细信息