我正在使用Spring JPA规范来创建条件查询。我的代码如下:
public CollectionWrapper<OrderTableItemDto> getOrders(Integer page,
Integer size,
String search,
OrderShow show) {
Pageable pageable = PageRequest.of(page, size, Sort.by(OrderEntity_.ID).descending());
try {
Specification<OrderEntity> specifications = buildOrderSpecification(show, search);
Page<OrderEntity> orders = orderDao.findAll(specifications, pageable);
List<OrderTableItemDto> result = orders.getContent().stream().map(order -> {
OrderTableItemDto orderTableItemDto = new OrderTableItemDto();
orderTableItemDto.setCreatedDate(order.getCreatedDate());
orderTableItemDto.setCustomerId(order.getCustomer().getId());
orderTableItemDto.setId(order.getId());
orderTableItemDto.setStatus(order.getStatus());
orderTableItemDto.setTotalCost(order.getTotalCost());
orderTableItemDto.setOrderType(order.getOrderType());
orderTableItemDto.setOrderTypeLabel(order.getOrderType().getLabel());
if(order.getOrderInShippingMethod() != null) {
orderTableItemDto.setShipped(OrderShippingStatus.DELIVERED.equals(order.getOrderInShippingMethod().getStatus()));
} else {
orderTableItemDto.setShipped(false);
}
StringBuilder sb = new StringBuilder();
sb.append("#")
.append(order.getId())
.append(" ");
if(order.getOrderType().equals(OrderType.WEB_STORE)) {
sb
.append(order.getBilling().getFirstName())
.append(" ")
.append(order.getBilling().getLastName());
} else {
sb.append(order.getCustomer().getFullName());
}
orderTableItemDto.setTitle(sb.toString());
return orderTableItemDto;
}).collect(Collectors.toList());
return new CollectionWrapper<>(result, orders.getTotalElements());
有人告诉我这是一种不好的方法,我应该使用投影(DTO)来从数据库中读取数据,因为创建实体并在之后进行映射非常昂贵。问题是我不知道如何将规格与DTO结合在一起。用包含嵌套DTO和许多属性的复杂DTO管理复杂和动态查询(来自用户输入等的过滤器)的最佳方法是什么?
我不赞成这样的说法,即创建实体要比直接使用DTO更快。在创建DTO之前,JPA仍必须提供中间表示。即使速度更快或使用较少的内存,问题仍然是:是否相关?
获取实体,然后创建DTO通常是浪费,因为实体通常具有比您实际需要的多得多的列。如果您在某处使用急切的访存,那么您还将进行不必要的联接。如果您要获取嵌套的集合或复杂的表达式,请签出Blaze-Persistence Entity-Views,这是一个在JPA之上运行的库,可让您将任意结构映射到实体模型。它使您可以将预测与业务逻辑脱钩,即可以将DTO应用于现有查询。您的用例的实体视图可能如下所示