我希望在我正在从事的项目中使用 CQRS,但是我目前正在努力寻找实现 CQRS 查询端的最佳方法。根据我有限的理解,有一个 Thin Data Layer(有时称为 Thin Read Layer),它查询数据库并返回一个 DTO 以及应用程序的 UI 层使用的查询结果。
由于这是一个 Java EE 应用程序,我正在开发 Thin Data Layer 使用 JPA 来查询数据库,使用EntityManager.createNamedQuery
该数据库返回一个包含结果的实体,然后我将其映射到 DTO。
鉴于应用程序的查询端应该是“只读的”,DTO 包含每个属性的 getter 但不包含 setter,以及用于在创建时填充属性的构造函数。
对于一个简单的查询,我可以使用构造函数将实体中的值手动映射到 DTO,但是这对于更复杂的查询是不切实际的,特别是当实体包含需要映射到对应的“一对多”关系时DTO。我已经研究过使用 Dozer 和 ModelMapper 等映射框架,但是它们似乎都依赖于具有设置器的 DTO,并且似乎没有使用构造函数。
下面的代码代表了我创建的两个实体和两个 DTO 的非常简化的视图,以帮助解释这种情况。
@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
}
我的问题是:
使用 CQRS 时,DTO 应该只有 getter 和构造函数,还是也可以接受 setter?
如果 DTO 理想情况下应该只有 getter 和构造函数,那么映射框架是否是填充 DTO 的最佳方式,其中实体返回包含“一对多”关系的复杂结果集?
有没有可以使用构造函数而不是设置器的映射框架?