JPA实体与CQRS中DTO的映射
Mapping between JPA entity and DTO in CQRS
我希望在我正在进行的项目中使用 CQRS,但是我目前正在努力寻找实现 CQRS 查询端的最佳方法。根据我有限的理解,有一个查询数据库的薄数据层(有时称为薄读取层)和 returns 一个具有查询结果的 DTO,由应用程序的 UI 层使用.
因为这是一个 Java EE 应用程序,我正在开发精简数据层,使用 JPA 查询数据库,使用 EntityManager.createNamedQuery
returns 一个包含我的结果的实体m 然后映射到 DTO。
鉴于应用程序的查询端应该是 "read only",DTO 包含每个属性的 getter 但没有 setter 和一个用于在创建时填充属性的构造函数。
对于简单的查询,我可以使用构造函数手动将实体中的值映射到 DTO,但这对于更复杂的查询来说并不实用,尤其是在实体包含 "one-to-many" 关系的情况下映射到相应的 DTO。我研究过使用映射框架,例如 Dozer 和 ModelMapper,但是它们似乎都依赖于具有 setter 的 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 和构造函数
或者也可以接受二传手吗?
如果理想情况下 DTO 应该只有 getter 和构造函数,那么
映射框架是填充实体所在的 DTO 的最佳方式
返回了一个包含 "one-to-many" 的复杂结果集
关系?
有没有可以使用构造函数的映射框架
比二传手?
- 最好的方法是只有 getter 和构造函数。那么你的 DTO 是 immutable.
- 您可以通过两种方式生成 DTO。一种是使用 JPA 和
select new my_package.MyDto(u.username, u.email) from User u
之类的查询。第二种对于包含许多 table 结果的更大的 dto 更受欢迎的是使用非 jpa 技术,如 MyBatis 或 SpringJdbcTemplate。第二种方式更有意义,因为您不会从数据库中检索不必要的数据。因此,由于性能原因,您应该只获取创建 DTO 所需的数据。
- 是 - 例如最流行的 JacksonMapper 可以使用构造函数而不是设置器。 Orika 等其他框架也可以创建此类映射。您可以在我的博客上找到详细信息 post - http://www.kubrynski.com/2015/02/datatransferobject-myth-busting.html
我希望在我正在进行的项目中使用 CQRS,但是我目前正在努力寻找实现 CQRS 查询端的最佳方法。根据我有限的理解,有一个查询数据库的薄数据层(有时称为薄读取层)和 returns 一个具有查询结果的 DTO,由应用程序的 UI 层使用.
因为这是一个 Java EE 应用程序,我正在开发精简数据层,使用 JPA 查询数据库,使用 EntityManager.createNamedQuery
returns 一个包含我的结果的实体m 然后映射到 DTO。
鉴于应用程序的查询端应该是 "read only",DTO 包含每个属性的 getter 但没有 setter 和一个用于在创建时填充属性的构造函数。
对于简单的查询,我可以使用构造函数手动将实体中的值映射到 DTO,但这对于更复杂的查询来说并不实用,尤其是在实体包含 "one-to-many" 关系的情况下映射到相应的 DTO。我研究过使用映射框架,例如 Dozer 和 ModelMapper,但是它们似乎都依赖于具有 setter 的 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 和构造函数 或者也可以接受二传手吗?
如果理想情况下 DTO 应该只有 getter 和构造函数,那么 映射框架是填充实体所在的 DTO 的最佳方式 返回了一个包含 "one-to-many" 的复杂结果集 关系?
有没有可以使用构造函数的映射框架 比二传手?
- 最好的方法是只有 getter 和构造函数。那么你的 DTO 是 immutable.
- 您可以通过两种方式生成 DTO。一种是使用 JPA 和
select new my_package.MyDto(u.username, u.email) from User u
之类的查询。第二种对于包含许多 table 结果的更大的 dto 更受欢迎的是使用非 jpa 技术,如 MyBatis 或 SpringJdbcTemplate。第二种方式更有意义,因为您不会从数据库中检索不必要的数据。因此,由于性能原因,您应该只获取创建 DTO 所需的数据。 - 是 - 例如最流行的 JacksonMapper 可以使用构造函数而不是设置器。 Orika 等其他框架也可以创建此类映射。您可以在我的博客上找到详细信息 post - http://www.kubrynski.com/2015/02/datatransferobject-myth-busting.html