У меня есть суперкласс AuditEntity
.
@Getter
@Setter
@MappedSuperclass
@EntityListeners(AuditEntityListener.class)
public abstract class AuditEntity {
public static final String ID = "id";
public static final String ORGANIZATION = "organization";
public static final String CREATED_BY = "createdBy";
public static final String MODIFIED_BY = "modifiedBy";
public static final String CREATED_DATETIME = "createdDatetime";
public static final String MODIFIED_DATETIME = "modifiedDatetime";
public static final String STATE = "state";
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "organization_id")
protected Organization organization;
@Column(name = "created_datetime")
protected Instant createdDatetime;
@Column(name = "modified_datetime")
protected Instant modifiedDatetime;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "created_by")
protected User createdBy;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "modified_by")
protected User modifiedBy;
@Enumerated(EnumType.STRING)
@Column(name = "state")
protected State state;
}
И объект расширяет суперкласс.
@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode(of = {"id"}, callSuper = false)
@Entity
@Table(name = "inventory_request")
public class InventoryRequest extends AuditEntity {
public static final String NAME = "name";
public static final String REQUESTER = "requester";
public static final String SOURCE = "source";
public static final String EVENT = "event";
public static final String TRANSFER = "transfers";
public static final String ASSIGNMENT = "assignment";
public static final String INVENTORY_REQUEST_STATUS = "status";
public static final String NOTES = "notes";
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "inventory_request_id")
private UUID id;
@Column(name = "name", nullable = false)
private String name;
@Column(name = "email", nullable = false)
private String email;
@ManyToOne(cascade = CascadeType.DETACH, fetch = FetchType.LAZY)
@JoinColumn(name = "requester_id")
private User requester;
@ManyToOne(cascade = CascadeType.DETACH, fetch = FetchType.LAZY)
@JoinColumn(name = "source_id")
@ApiModelProperty(hidden = true)
private User source;
@Enumerated(EnumType.STRING)
@Column(name = "status", nullable = false, length = 24)
private InventoryRequestStatus status;
@Column(name = "carrier")
private String carrier;
@Column(name = "tracking_number")
private String trackingNumber;
@Column(name = "note", length = 1024)
private String note;
@JsonManagedReference
@ManyToOne(cascade = CascadeType.DETACH, fetch = FetchType.LAZY)
@JoinColumn(name = "event_id")
private Event event;
@Column(name = "number", nullable = false)
private Long number;
@Column(name = "tracking_enabled", nullable = false)
private Boolean trackingEnabled;
@JsonManagedReference
@OneToMany(fetch = FetchType.LAZY, mappedBy = Transfer.INVENTORY_REQUEST)
private Set<Transfer> transfers;
@JsonManagedReference
@OneToMany(fetch = FetchType.LAZY, mappedBy = InventoryRequestAssignment.INVENTORY_REQUEST)
private Set<InventoryRequestAssignment> assignment;
@JsonManagedReference
@OneToMany(fetch = FetchType.LAZY, mappedBy = InventoryRequestNote.INVENTORY_REQUEST)
private Set<InventoryRequestNote> notes;
}
Это класс, который я хочу выбрать с критериями api.
@NoArgsConstructor
@Getter
@Setter
public class InventoryRequestDTO extends InventoryRequest {
public InventoryRequestDTO(InventoryRequest inventoryRequest,
Long completeSetsQuantity,
Long specificProductQuantity) {
super(inventoryRequest.getId(),
inventoryRequest.getName(),
inventoryRequest.getEmail(),
inventoryRequest.getRequester(),
inventoryRequest.getSource(),
inventoryRequest.getStatus(),
inventoryRequest.getCarrier(),
inventoryRequest.getTrackingNumber(),
inventoryRequest.getNote(),
inventoryRequest.getEvent(),
inventoryRequest.getNumber(),
inventoryRequest.getTrackingEnabled(),
inventoryRequest.getTransfers(),
inventoryRequest.getAssignment(),
inventoryRequest.getNotes());
this.completeSetsQuantity = completeSetsQuantity;
this.specificProductQuantity = specificProductQuantity;
}
private Long completeSetsQuantity;
private Long specificProductQuantity;
}
И это метод, который я пытался сделать.
@Transactional
public Page<? extends InventoryRequest> getInventoryRequestPage(InventoryRequestSearchParams searchParams, Pageable pageable) {
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<InventoryRequest> query = builder.createQuery(InventoryRequest.class);
Root<InventoryRequest> root = query.from(InventoryRequest.class);
Join<InventoryRequest, InventoryRequestAssignment> assignmentJoin = root.join(InventoryRequest.ASSIGNMENT, JoinType.LEFT);
Expression<Long> specificProductQuantity = builder.count(builder.selectCase()
.when(assignmentJoin.get(InventoryRequestAssignment.CATALOG).isNotNull(), 1)
.otherwise(0));
Expression<Long> completeSetsQuantity = builder.count(builder.selectCase()
.when(assignmentJoin.get(InventoryRequestAssignment.CATALOG).isNull(), 1)
.otherwise(0));
Predicate predicate = InventoryRequestSpecificationComposer.builder()
.searchParams(searchParams)
.build()
.compose()
.toPredicate(root, query, builder);
query.select(
builder.construct(InventoryRequestDTO.class,
root,
completeSetsQuantity,
specificProductQuantity))
.where(predicate);
Query q = entityManager.createQuery(query);
int totalRows = q.getResultList().size();
q.setFirstResult(pageable.getPageNumber() * pageable.getPageSize());
q.setMaxResults(pageable.getPageSize());
return new PageImpl<>(q.getResultList(), pageable, totalRows);
}
Но я получаю это исключение.
org.hibernate.QueryException: query specified join fetching, but the owner of the fetched association was not present in the select list [FromElement{explicit,not a collection join,fetch join,fetch non-lazy properties,classAlias=generatedAlias2,role=com.connectsx.core.model.entity.InventoryRequest.createdBy,tableName=users,tableAlias=user2_,origin=inventory_request inventoryr0_,columns={inventoryr0_.created_by ,className=com.connectsx.core.model.entity.User}}]
Также у меня есть построитель спецификаций для объекта аудита , который извлекает свойства organization
, created_by
, modified_by
. Но если я выберу InventoryRequest.class
, он работает нормально, а с DTO не работает.