我希望在我正在从事的项目中使用 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 的最佳方式,其中实体返回包含“一对多”关系的复杂结果集?
有没有可以使用构造函数而不是设置器的映射框架?