Java JPA-带左连接和计数的TypedQuery

Java JPA-带左连接和计数的TypedQuery,java,database,hibernate,jpa,hql,Java,Database,Hibernate,Jpa,Hql,我一直在尝试使用TypedQuery和Criteria Builder构建下面的SQL: select a.id, a.numeroAvisoPagamento, a.industria_id, a.varejo_id, a.dataAvisoPagamento, a.statusAvisoPagamento, a.dataUploadArquivo, a.dataIm

我一直在尝试使用TypedQuery和Criteria Builder构建下面的SQL:

select
        a.id,
        a.numeroAvisoPagamento,
        a.industria_id,
        a.varejo_id,
        a.dataAvisoPagamento,
        a.statusAvisoPagamento,
        a.dataUploadArquivo,
        a.dataImportacaoArquivo,
        a.dataConciliacaoAviso,
        count(c.avisoPagamento_id) as qtdeNotas, 
    from
        AvisoPagamento a  
    left join
        LoteAvisoPagamento l 
            ON l.codigoAviso = a.numeroAvisoPagamento 
    left join
        Cobranca c 
            ON c.avisoPagamento_id = l.id 
    where
        a.industria_id = ? 
        and a.varejo_id = ? 
        and a.numeroAvisoPagamento = ? 
        and a.dataAvisoPagamento between ? and ? 
    group by
        a.id,
        a.numeroAvisoPagamento,
        a.numeroAvisoPagamento,
        a.industria_id,
        a.varejo_id,
        a.dataAvisoPagamento,
        a.statusAvisoPagamento,
        a.dataUploadArquivo,
        a.dataImportacaoArquivo,
        a.dataConciliacaoAviso
型号

AvisoPagamento

@Entity(name = "AvisoPagamento")
public class AvisoPagamento {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;

@OneToMany(mappedBy = "avisoPagamento", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private List<CobrancaAvisoPagamento> cobrancas;

@OneToMany(mappedBy = "avisoPagamento", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@OrderBy("dataAcao ASC")
@JsonIgnore(accept={"AvisoPagamentoController.*"})
private List<LogAvisoPagamento> logAvisoPagamento;
}
@Entity(name = "LoteAvisoPagamento")
public class LoteAvisoPagamento {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;

@Column(nullable = false)
private Long codigoAviso;

}
Cobranca

public class Cobranca {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;

@ManyToOne(fetch = FetchType.LAZY, optional = true)
@JoinColumn(name = "avisoPagamento_id")
@JsonIgnore(accept = { "CobrancaLoteController.listaCobrancas", "CobrancaAdmController.*",
        "ConciliacaoController.*", "CobrancaIndController.*" })
private LoteAvisoPagamento avisoPagamento;
}
我有两个问题:

  • 实体LoteAvisoPagamento和AvisoPagamento之间没有关系,因此我使用两列“强制”合并:在LoteAvisoPagamento.CODIGAVISO=AvisoPagamento.numeroAvisoPagamento上。可以很好地使用SQL Native
  • 我需要计算表Cobranca中的记录,所以我使用了count(c.avisoPagamento_id)
  • 我想将此SQL重新连接到TypedQuery和CriteriaBuilder,因此我尝试了以下方法:

    //Create Criteria Builder
            final CriteriaBuilder builder = manager.getCriteriaBuilder();
            //Create CriteriaQuery da Classe AvisoPagamento
            final CriteriaQuery<AvisoPagamento> query = builder.createQuery(AvisoPagamento.class);
            //Create from
            final Root<AvisoPagamento> rootAviso = query.from(AvisoPagamento.class);
    
            //Left Join Lote Aviso Pagamento
            Root<LoteAvisoPagamento> rootLoteAviso = query.from(LoteAvisoPagamento.class);
    
            final Predicate predicateLeftJoin = builder.equal(rootAviso.get("numeroAvisoPagamento"), rootLoteAviso.get("codigoAviso"));
    
            //Conditions
            Predicate predicateAvisoPagamento = builder.and();
    
            //Join Selects
            Predicate criteria = builder.conjunction();
            criteria = builder.and(criteria, predicateAvisoPagamento);
            criteria = builder.and(criteria, predicateLeftJoin);
    
            //Passou a Industria
            if (industria != null){
                 predicateAvisoPagamento = builder.and(predicateAvisoPagamento, builder.equal(rootAviso.get("industria"), industria));
            }
            //Passou o Varejo
            if (varejo != null){
                predicateAvisoPagamento = builder.and(predicateAvisoPagamento, builder.equal(rootAviso.get("varejo"), varejo));
            }
            //Passou o numero do Aviso
            if (numeroAviso != null){
                predicateAvisoPagamento = builder.and(predicateAvisoPagamento, builder.equal(rootAviso.get("numeroAvisoPagamento"), numeroAviso));
            }
    
            //Passou as Datas De e Ate
            if (dataDe != null && dataAte != null){
                predicateAvisoPagamento = builder.between(rootAviso.<Date>get("dataAvisoPagamento"), dataDe , dataAte);
            }
    
    
            //TypedQuery eh mais robusto, a checagem de tipo é feito na compilacao, eliminando alguns
            //tipos de erros
            final TypedQuery<AvisoPagamento> typedQuery = manager.createQuery(
                query.select(rootAviso).distinct(true)
                .where( criteria )
                .orderBy(builder.desc(rootAviso.get("dataConciliacaoAviso")))
            );
    
    
            //return List
            final List<AvisoPagamento> results = typedQuery.getResultList();
    
            return results;
    
    如何使用TypedQuery计算表Cobranca中的记录,以及如何解决此问题:

     where
                1=1 
                and 1=1
    

    奇怪的是,我读了很多关于TypedQuery的书,但我被困在了我认为ON子句只处理JPA2.1版本中的关系

    所以到现在为止你还不能用

    具有两列的并集:在LoteAvisoPagamento.codigoAviso=AvisoPagamento.numerioavisopagamento上

    因为JPA2.1(最新版本)不支持这一点

    因此,它在标准或JPQL上不起作用

    注意:交叉连接不需要ON子句,这就是为什么您在生成的查询中看到它,而且您也不能执行左连接 你使用的标准(不可能)总是这样 生成为交叉连接

    内部联接和左联接需要实体之间的关系

    尝试您的下一个JPQL,并测试它是否有效(我认为它不会起作用),它很简单,但应该与您想要做的类似(至少到目前为止在一个条件下类似)

    用任何有效值替换:numerioaviso,然后将其作为entityManager.createQuery进行测试(将查询放在此处

    不管怎样,我在我这边测试了不同的实体,但逻辑相同,我得到了一个异常

    注意:我将JPA与Hibernate provider一起使用

    这是我得到的例外

    原因:org.hibernate.hql.internal.ast.QuerySyntaxException:应加入的路径

    所以它期望类似的东西(您的实体不支持)

    左连接aviso.loteAvisoPagamento loteAviso

    在下一个查询中

    SELECT aviso.id, aviso.numeroAvisoPagamento, loteAviso.id
    FROM AvisoPagamento aviso
    LEFT JOIN aviso.loteAvisoPagamento loteAviso
    ON loteAviso.codigoAviso = aviso.numeroAvisoPagamento
    WHERE aviso.numeroAvisoPagamento = :numeroAviso
    

    我认为ON条款只适用于JPA2.1版本中的关系

    所以到现在为止你还不能用

    具有两列的并集:在LoteAvisoPagamento.codigoAviso=AvisoPagamento.numerioavisopagamento上

    因为JPA2.1(最新版本)不支持这一点

    因此,它在标准或JPQL上不起作用

    注意:交叉连接不需要ON子句,这就是为什么您在生成的查询中看到它,而且您也不能执行左连接 你使用的标准(不可能)总是这样 生成为交叉连接

    内部联接和左联接需要实体之间的关系

    尝试您的下一个JPQL,并测试它是否有效(我认为它不会起作用),它很简单,但应该与您想要做的类似(至少到目前为止在一个条件下类似)

    用任何有效值替换:numerioaviso,然后将其作为entityManager.createQuery进行测试(将查询放在此处

    不管怎样,我在我这边测试了不同的实体,但逻辑相同,我得到了一个异常

    注意:我将JPA与Hibernate provider一起使用

    这是我得到的例外

    原因:org.hibernate.hql.internal.ast.QuerySyntaxException:应加入的路径

    所以它期望类似的东西(您的实体不支持)

    左连接aviso.loteAvisoPagamento loteAviso

    在下一个查询中

    SELECT aviso.id, aviso.numeroAvisoPagamento, loteAviso.id
    FROM AvisoPagamento aviso
    LEFT JOIN aviso.loteAvisoPagamento loteAviso
    ON loteAviso.codigoAviso = aviso.numeroAvisoPagamento
    WHERE aviso.numeroAvisoPagamento = :numeroAviso
    

    @mibrahim.iti告诉左边的JOIN或internal需要实体之间的关系,所以我使用本机SQL来实现这一点,这里是我的最终解决方案:

    //Sql Log
            final StringBuilder sqlLog = new StringBuilder();
            sqlLog.append("select l from LogAvisoPagamento l where l.avisoPagamento.id = :idAviso  order by l.dataAcao ");
    
            final Query queryLog = manager.createQuery(sqlLog.toString());
    
            //Sql Aviso
            final StringBuilder sql = new StringBuilder();
            sql.append("select a.id, ")
            .append(" a.numeroAvisoPagamento, ")
            .append(" a.industria_id, ")
            .append(" a.varejo_id, ")
            .append(" a.dataAvisoPagamento, ")
            .append(" a.statusAvisoPagamento, ")
            .append(" a.dataUploadArquivo, ")
            .append(" a.dataImportacaoArquivo, ")
            .append(" a.dataConciliacaoAviso, ")
            .append(" count(c.avisoPagamento_id) as qtdeNotas, ")
            .append(" r.valorTotalBruto ")
            .append(" from AvisoPagamento a ")
            .append(" left join ResumoAvisoPagamento r ON r.avisoPagamento_id = a.id ")
            .append(" left join LoteAvisoPagamento l ON l.codigoAviso = a.numeroAvisoPagamento")
            .append(" left join Cobranca c ON c.avisoPagamento_id = l.id");
    
            boolean where = false;
    
            //Passou a Industria
            if (industria != null){
                sql.append(" where a.industria_id = :idIndustria");
                where = true;
            }
    
            //Passou o Varejo
            if (varejo != null){
                if (!where){
                    sql.append(" where a.varejo_id = :idVarejo");
                    where = true;
                }else{
                    sql.append(" and a.varejo_id = :idVarejo");
                }
            }
    
            //Passou o numero do Aviso
            if (numeroAviso != null){
                if (!where){
                    sql.append(" where a.numeroAvisoPagamennto = :numeroAvisoPagamento");
                    where = true;
                }else{
                    sql.append(" and a.numeroAvisoPagamento = :numeroAvisoPagamento");
                }
    
            }
    
            //Passou as Datas De e Ate
            if (dataDe != null && dataAte != null){
                if (!where){
                    where = true;
                    sql.append(" where a.dataAvisoPagamento between :dataDe and :dataAte");
                }else{
                    sql.append(" and a.dataAvisoPagamento between :dataDe and :dataAte");
                }
            }
    
            sql.append(" group by a.id, a.numeroAvisoPagamento, ")
            .append(" a.numeroAvisoPagamento, ")
            .append(" a.industria_id, ")
            .append(" a.varejo_id, ")
            .append(" a.dataAvisoPagamento, ")
            .append(" a.statusAvisoPagamento, ")
            .append(" a.dataUploadArquivo, ")
            .append(" a.dataImportacaoArquivo, ")
            .append(" a.dataConciliacaoAviso, ")
            .append(" r.valorTotalBruto ");
    
            final Query query = manager.createNativeQuery(sql.toString());
    
            //Passou a Industria
            if (industria != null){
                query.setParameter("idIndustria", industria.getId());
            }
    
            //Passou o Varejo
            if (varejo != null){
                query.setParameter("idVarejo", varejo.getId());
            }
    
            //Passou o numero do Aviso
            if (numeroAviso != null){
                query.setParameter("numeroAvisoPagamento", numeroAviso);
            }
    
            //Passou as Datas De e Ate
            if (dataDe != null && dataAte != null){
                query.setParameter("dataDe", dataDe);
                query.setParameter("dataAte", dataAte);
            }
    
            final List<AvisoPagamento> avisosPagamentos = new ArrayList<AvisoPagamento>();
            //Percorrendo os Registros
            for (final Object array : query.getResultList()){
    
                final Object[] arrayAviso = (Object[]) array;
    
                final ResumoAvisoPagamento resumo = new ResumoAvisoPagamento();
                resumo.setValorTotalBruto((BigDecimal) arrayAviso[10]);
    
                final AvisoPagamento avisoPagamento = new AvisoPagamento();
    
                final BigInteger id = new BigInteger(arrayAviso[0].toString());
                avisoPagamento.setId(id.longValue());
                avisoPagamento.setNumeroAvisoPagamento((String) arrayAviso[1]);
                avisoPagamento.setDataAvisoPagamento((Date) arrayAviso[4]);
                avisoPagamento.setStatusAvisoPagamento(StatusAvisoPagamento.valueOf(arrayAviso[5].toString()));
                avisoPagamento.setDataUploadArquivo((Date) arrayAviso[6]);
                avisoPagamento.setDataImportacaoArquivo((Date) arrayAviso[7]);
                avisoPagamento.setDataConciliacaoAviso((Date) arrayAviso[8]);
    
                final BigInteger qtde = new BigInteger(arrayAviso[9].toString());
                avisoPagamento.setQtdeNotas(qtde.intValue());
    
                queryLog.setParameter("idAviso", avisoPagamento.getId());
                //Get Log
                final List<LogAvisoPagamento> logs = queryLog.getResultList();
    
                avisoPagamento.setLogAvisoPagamento(logs);
                avisoPagamento.setResumoAvisoPagamento(resumo);
                avisosPagamentos.add(avisoPagamento);
            }
    
            return avisosPagamentos;
    
    //Sql日志
    最终StringBuilder sqlLog=新StringBuilder();
    append(“从LogAvisoPagamento l中选择l,其中l.avisoPagamento.id=:idAviso order by l.dataAcao”);
    最终查询queryLog=manager.createQuery(sqlLog.toString());
    //Sql Aviso
    最终StringBuilder sql=新StringBuilder();
    追加(“选择a.id”)
    .append(“a.numerioavisopagamento,”)
    .append(“a.industria_id,”)
    .append(“a.varejo_id”)
    .append(“a.dataAvisoPagamento,”)
    .append(“a.statusAvisoPagamento,”)
    .append(“a.dataUploadArquivo,”)
    .append(“a.dataimportacoarquivo,”)
    .append(“a.dataconciliacaoviso”)
    .append(“count(c.avisoPagamento_id)作为qtdeNotas,”)
    .附加(“r.valorTotalBruto”)
    .附加(“来自AvisoPagamento a”)
    .append(“r.avisoPagamento_id=a.id上的左连接ResumoAvisoPagamento r”)
    .append(“l.codigoavisopagamento=a.numerioavisopagamento上的左连接LoteAvisoPagamento l”)
    .append(“c.avisoPagamento_id=l.id上的左连接Cobranca c”);
    布尔值,其中=false;
    //帕苏工业
    如果(industria!=null){
    append(“其中a.industria_id=:idIndustria”);
    其中=真;
    }
    //帕索瓦雷霍
    if(varejo!=null){
    如果(!在哪里){
    append(“其中a.varejo_id=:idVarejo”);
    其中=真;
    }否则{
    append(“and a.varejo_id=:idVarejo”);
    }
    }
    //我是阿维索先生
    如果(numeroAviso!=null){
    如果(!在哪里){
    append(“其中a.numeravisopagamento=:numeravisopagamento”);
    其中=真;
    }否则{
    append(“and a.numerioavisopagamento=:numerioavisopagamento”);
    }
    }
    //作为数据的通行证
    如果(数据)
    
    //Sql Log
            final StringBuilder sqlLog = new StringBuilder();
            sqlLog.append("select l from LogAvisoPagamento l where l.avisoPagamento.id = :idAviso  order by l.dataAcao ");
    
            final Query queryLog = manager.createQuery(sqlLog.toString());
    
            //Sql Aviso
            final StringBuilder sql = new StringBuilder();
            sql.append("select a.id, ")
            .append(" a.numeroAvisoPagamento, ")
            .append(" a.industria_id, ")
            .append(" a.varejo_id, ")
            .append(" a.dataAvisoPagamento, ")
            .append(" a.statusAvisoPagamento, ")
            .append(" a.dataUploadArquivo, ")
            .append(" a.dataImportacaoArquivo, ")
            .append(" a.dataConciliacaoAviso, ")
            .append(" count(c.avisoPagamento_id) as qtdeNotas, ")
            .append(" r.valorTotalBruto ")
            .append(" from AvisoPagamento a ")
            .append(" left join ResumoAvisoPagamento r ON r.avisoPagamento_id = a.id ")
            .append(" left join LoteAvisoPagamento l ON l.codigoAviso = a.numeroAvisoPagamento")
            .append(" left join Cobranca c ON c.avisoPagamento_id = l.id");
    
            boolean where = false;
    
            //Passou a Industria
            if (industria != null){
                sql.append(" where a.industria_id = :idIndustria");
                where = true;
            }
    
            //Passou o Varejo
            if (varejo != null){
                if (!where){
                    sql.append(" where a.varejo_id = :idVarejo");
                    where = true;
                }else{
                    sql.append(" and a.varejo_id = :idVarejo");
                }
            }
    
            //Passou o numero do Aviso
            if (numeroAviso != null){
                if (!where){
                    sql.append(" where a.numeroAvisoPagamennto = :numeroAvisoPagamento");
                    where = true;
                }else{
                    sql.append(" and a.numeroAvisoPagamento = :numeroAvisoPagamento");
                }
    
            }
    
            //Passou as Datas De e Ate
            if (dataDe != null && dataAte != null){
                if (!where){
                    where = true;
                    sql.append(" where a.dataAvisoPagamento between :dataDe and :dataAte");
                }else{
                    sql.append(" and a.dataAvisoPagamento between :dataDe and :dataAte");
                }
            }
    
            sql.append(" group by a.id, a.numeroAvisoPagamento, ")
            .append(" a.numeroAvisoPagamento, ")
            .append(" a.industria_id, ")
            .append(" a.varejo_id, ")
            .append(" a.dataAvisoPagamento, ")
            .append(" a.statusAvisoPagamento, ")
            .append(" a.dataUploadArquivo, ")
            .append(" a.dataImportacaoArquivo, ")
            .append(" a.dataConciliacaoAviso, ")
            .append(" r.valorTotalBruto ");
    
            final Query query = manager.createNativeQuery(sql.toString());
    
            //Passou a Industria
            if (industria != null){
                query.setParameter("idIndustria", industria.getId());
            }
    
            //Passou o Varejo
            if (varejo != null){
                query.setParameter("idVarejo", varejo.getId());
            }
    
            //Passou o numero do Aviso
            if (numeroAviso != null){
                query.setParameter("numeroAvisoPagamento", numeroAviso);
            }
    
            //Passou as Datas De e Ate
            if (dataDe != null && dataAte != null){
                query.setParameter("dataDe", dataDe);
                query.setParameter("dataAte", dataAte);
            }
    
            final List<AvisoPagamento> avisosPagamentos = new ArrayList<AvisoPagamento>();
            //Percorrendo os Registros
            for (final Object array : query.getResultList()){
    
                final Object[] arrayAviso = (Object[]) array;
    
                final ResumoAvisoPagamento resumo = new ResumoAvisoPagamento();
                resumo.setValorTotalBruto((BigDecimal) arrayAviso[10]);
    
                final AvisoPagamento avisoPagamento = new AvisoPagamento();
    
                final BigInteger id = new BigInteger(arrayAviso[0].toString());
                avisoPagamento.setId(id.longValue());
                avisoPagamento.setNumeroAvisoPagamento((String) arrayAviso[1]);
                avisoPagamento.setDataAvisoPagamento((Date) arrayAviso[4]);
                avisoPagamento.setStatusAvisoPagamento(StatusAvisoPagamento.valueOf(arrayAviso[5].toString()));
                avisoPagamento.setDataUploadArquivo((Date) arrayAviso[6]);
                avisoPagamento.setDataImportacaoArquivo((Date) arrayAviso[7]);
                avisoPagamento.setDataConciliacaoAviso((Date) arrayAviso[8]);
    
                final BigInteger qtde = new BigInteger(arrayAviso[9].toString());
                avisoPagamento.setQtdeNotas(qtde.intValue());
    
                queryLog.setParameter("idAviso", avisoPagamento.getId());
                //Get Log
                final List<LogAvisoPagamento> logs = queryLog.getResultList();
    
                avisoPagamento.setLogAvisoPagamento(logs);
                avisoPagamento.setResumoAvisoPagamento(resumo);
                avisosPagamentos.add(avisoPagamento);
            }
    
            return avisosPagamentos;