I would like to replicate a query that runs happily in both MySQL and H2:
SELECT
pedido_linha.produto_id AS material,
COALESCE(pedido_linha.unidade_medida_id, "UN") AS uom,
pedido_linha.data_pedido AS referenceDate,
SUM(COALESCE(pedido_linha.quantidade, 0)) AS totalQuantity,
SUM(COALESCE(pedido_linha.valor_total, 0)) AS totalGross,
SUM(COALESCE(pedido_linha.valor_total, 0) - COALESCE(pedido_linha.valor_descontos, 0) -
COALESCE(pedido_linha.valor_impostos, 0)) AS totalNet,
SUM(COALESCE(pedido_linha.valor_custo, 0)) AS totalCogs
FROM pedido_linha
GROUP BY pedido_linha.produto_id, pedido_linha.data_pedido, COALESCE(pedido_linha.unidade_medida_id, "UN");
As an example the query runs fine in MySQL, even though some Group By fields are empty:
The following attempt has been made extract the grouped results in a JPA closed projection:
public interface AggregatedByMaterialUOMDate {
Produto getMaterial();
UnidadeMedida getUom();
LocalDate getReferenceDate();
Float getTotalQuantity();
Float getTotalGross();
Float getTotalNet();
Float getTotalCogs();
}
Along with the repository query:
@Repository
public interface PedidoLinhaRepository extends JpaRepository<PedidoLinha, PedidoLinha.PedidoLinhaCompositeKey> {
@Query("SELECT pl.produto AS material, "
+ "COALESCE(pl.unidadeMedida, :unidadeMedidaPadrao) AS uom, "
+ "pl.dataPedido AS referenceDate, "
+ "SUM(COALESCE(pl.quantidade, 0)) AS totalQuantity, "
+ "SUM(COALESCE(pl.valorTotal, 0)) AS totalGross, "
+ "SUM(COALESCE(pl.valorTotal, 0) - COALESCE(pl.valorDescontos, 0) - COALESCE(pl.valorImpostos, 0)) AS totalNet, "
+ "SUM(COALESCE(pl.valorCusto, 0)) AS totalCogs "
+ "FROM PedidoLinha pl "
+ "GROUP BY pl.produto, pl.dataPedido, COALESCE(pl.unidadeMedida, :unidadeMedidaPadrao)")
List<AggregatedByMaterialUOMDate> consolidatedSelloutByMaterialUOMDayAtLocation(@Param("unidadeMedidaPadrao") UnidadeMedida unidadeMedidaPadrao);
}
The JPQL query above returns a list with 0 elements, thus inconsistent with the native query previously shown.
We have attempted to change COALESCE(pl.unidadeMedida, :unidadeMedidaPadrao) to simply pl.unidadeMedida (both in the SELECT and GROUP BY clauses), with no success.
The query successfully returned all values only when all references to pl.unidadeMedida were completely removed from both clauses.
Below is a sample of the PedidoLinha (referenced by pl in the query) class showing the reference to UnidadeMedida:
@Getter
@Setter
@NoArgsConstructor
@RequiredArgsConstructor
@EqualsAndHashCode(of = "pedidoLinhaCompositeKey")
@Entity
public class PedidoLinha {
@EmbeddedId
@NonNull // torna campo obrigatório e parâmetro do construtor gerado pelo @Data (lombok)
private PedidoLinhaCompositeKey pedidoLinhaCompositeKey;
@Data // lombok: @ToString, @EqualsAndHashCode, @Getter on all fields @Setter on all non-final fields, and @RequiredArgsConstructor
@NoArgsConstructor
@RequiredArgsConstructor
@Embeddable
@EqualsAndHashCode
public static class PedidoLinhaCompositeKey implements Serializable {
@NonNull // torna campo obrigatório e parâmetro do construtor gerado pelo @Data (lombok)
private String id;
@ManyToOne(optional = false, fetch = FetchType.LAZY)
@NonNull // torna campo obrigatório e parâmetro do construtor gerado pelo @Data (lombok)
private Pedido pedido;
}
@ManyToOne(optional = false)
private Produto produto;
@ManyToOne
private UnidadeMedida unidadeMedida;
public UnidadeMedida getUnidadeMedida() {
return (unidadeMedida == null) ? new UnidadeMedida("UN") : unidadeMedida;
}
// rest of the entity code
}
UnidadeMedida class
@Getter
@Setter
@EqualsAndHashCode(of = "id")
@NoArgsConstructor
@Entity
public class UnidadeMedida {
@Id
private String id;
private String descricao;
public UnidadeMedida(String id) {
this.id = id;
}
}
What could be happening? I believe this could be a Hibernate bug but could not find any reference to this issue.