我正在开发一个 Spring Boot 应用程序,使用 Blaze Persistence 构建一个复杂的条件查询来获取分页结果。但是,我遇到一个错误,指出:“查询生成器的项目顺序不能保证生成唯一的元组!还请考虑按实体标识符排序!”
以下是我的实体和我正在使用的条件查询的详细信息:
@Getter
@Setter
@Entity
@Table(name = "orders")
public class OrderEntity {
@Id
private Long orderId;
private String orderCode;
@OneToMany(mappedBy = "orderEntity", cascade = CascadeType.ALL, orphanRemoval = true)
private List<OrderAttribute> attributes = new ArrayList<>();
@OneToMany(mappedBy = "orderEntity", cascade = CascadeType.ALL, orphanRemoval = true)
private List<OrderAction> actions = new ArrayList<>();
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "issue_type_id", nullable = false)
private IssueType issueType;
}
@Getter
@Setter
@Entity
public class OrderAction {
@Id
private Long actionId;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "order_id", nullable = false)
private OrderEntity orderEntity;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "current_location_id", nullable = false)
private Location currentLocation;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "next_location_id", nullable = false)
private Location nextLocation;
}
@Getter
@Setter
@Entity
public class OrderAttribute {
@Id
private Long attributeId;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "order_id", nullable = false)
private OrderEntity orderEntity;
private String key;
private String value;
}
@Getter
@Setter
@Entity
public class IssueType {
@Id
private Long typeId;
@Column(nullable = false, unique = true)
private String type;
}
@Getter
@Setter
@Entity
public class Location {
@Id
private Integer locationId;
private String locationCode;
private String name;
private Integer parentLocationId;
}
@Component
public class OrderRepositoryCustomImpl implements OrderRepositoryCustom {
@PersistenceContext
private EntityManager em;
private final CriteriaBuilderFactory cbf;
public OrderRepositoryCustomImpl(EntityManager em, CriteriaBuilderFactory cbf) {
this.em = em;
this.cbf = cbf;
}
@Override
public Page<OrderListProjection> search(SearchRequest searchRequest, Pageable pageable) {
CriteriaBuilder<Tuple> cb = cbf.create(em, Tuple.class)
.from(OrderEntity.class, "o")
.select("o.orderId", "orderId")
.select("o.orderCode", "orderCode")
.select("loc.locationId", "nextLocationId")
.select("loc.name", "nextLocationName")
.select("it.type", "issueType")
.select("oa.value", "attributeValue")
.select("loc.parentLocationId", "parentLocationId")
.select("loc.name", "parentLocationName")
.select("loc.locationCode", "locationCode")
.innerJoin("o.issueType", "it")
.leftJoinLateralOnEntitySubquery("o.actions", "topAction", "action")
.orderByDesc("action.actionId")
.setMaxResults(1)
.end()
.on("1").eqExpression("1")
.end()
.leftJoin("topAction.nextLocation", "loc")
.leftJoinOnEntitySubquery("o", OrderAttribute.class, "oa")
.end()
.on("oa.orderEntity").eqExpression("o")
.on("oa.key").eq("attributeKey").end();
if (searchRequest.getIssueType() != null) {
cb.where("it.type").eq(searchRequest.getIssueType());
}
if (searchRequest.getParentLocationId() != null) {
cb.where("loc.parentLocationId").eq(searchRequest.getParentLocationId());
}
if (searchRequest.getAttributeValue() != null) {
cb.where("oa.value").eq(searchRequest.getAttributeValue());
}
PaginatedCriteriaBuilder<Tuple> builder = cb.page((int) pageable.getOffset(), pageable.getPageSize());
pageable.getSort().forEach(order -> {
String property = order.getProperty();
if (order.isAscending()) {
builder.orderByAsc("o." + property);
} else {
builder.orderByDesc("o." + property);
}
});
builder.orderByAsc("o.orderId");
PagedList<Tuple> resultList = builder.withKeysetExtraction(true).getResultList();
List<OrderListProjection> list = resultList.stream()
.map(tuple -> new OrderListProjection(
tuple.get("orderId", Long.class),
tuple.get("orderCode", String.class),
tuple.get("nextLocationId", Integer.class),
tuple.get("nextLocationName", String.class),
tuple.get("issueType", String.class),
tuple.get("attributeValue", String.class),
tuple.get("parentLocationId", Integer.class),
tuple.get("parentLocationName", String.class),
tuple.get("locationCode", String.class)))
.toList();
return new PageImpl<>(list, pageable, resultList.getTotalSize());
}
}
错误:查询生成器的项目顺序不能保证生成唯一的元组!还请考虑按实体标识符排序!
我尝试调整 order by 子句以包含实体标识符,但问题仍然存在。
pageable.getSort().forEach(order -> {
String property = order.getProperty();
if (order.isAscending()) {
builder.orderByAsc("o." + property);
} else {
builder.orderByDesc("o." + property);
}
});
builder.orderByAsc("o.orderId");
我尝试删除上面的代码,问题仍然存在。
我希望查询执行时不会出现错误并返回唯一的元组进行分页。
如何解决在 Blaze 持久性条件查询中按多个字段排序时确保元组唯一的问题?任何关于我所缺少的内容或如何调整我的查询的指导将不胜感激。
您必须使用
pageBy
方法并告诉 Blaze-Persistence 您想要分页的 id 属性。由于您的查询不是直接获取实体,因此 Blaze-Persistence 本身无法解决这个问题。
虽然您正在使用投影,为什么不使用 Blaze-Persistence Entity-Views 呢?它还与 Spring Data 进行了很好的集成,可以处理所有分页细节。您只需传递 Spring 数据
Pageable
。