JPA 本机查询问题

Posted

技术标签:

【中文标题】JPA 本机查询问题【英文标题】:JPA Native Query Issue 【发布时间】:2013-04-29 11:34:57 【问题描述】:

我在尝试使用 SQL SERVER 2008 数据库执行本机查询时遇到了 JPA 问题。我真的不明白发生了什么。 当我直接在数据库中执行查询时,我得到了以下结果(这是我所期望的):

DS  Node    Total   MinDate     MaxDate
EMM CCND    7796    2013-04-16  2013-04-22
EMM CCNV    12049   2013-04-16  2013-04-22
EMM CGSN    1252    2013-04-16  2013-04-22
EMM MSC     7456    2013-04-16  2013-04-22
EMM SMSC    3999    2013-04-16  2013-04-22

但在代码中,当我从我的 EntityManager 中检索数据时,结果并不相同。 我得到的是以下内容:

DS  Node    Total   MinDate     MaxDate
EMM CCND    7796    2013-04-16  2013-04-22
EMM CCND    7796    2013-04-16  2013-04-22
EMM CCND    7796    2013-04-16  2013-04-22
EMM CCND    7796    2013-04-16  2013-04-22
EMM CCND    7796    2013-04-16  2013-04-22

我在同一行得到相同的结果。很奇怪... 请,有人可以帮助我了解问题所在。我怀疑 PrimeFaces subtable 组件,无法显示好的数据,但现在我确定问题来自 JPA Native Query。 请参阅下面我正在使用的查询:

"select distinct DownStream.IDDownStream as DownStream, PortailMediation.IDNoeudOrigineCDR as Node, COUNT(CDR.NomSortie) as TotalFiles," + 
" MIN(convert(varchar(19),DateCDR,120)) as MinDate, MAX(convert(varchar(19),DateCDR,120)) as MaxDate" + 
" from DownStream, CDR, Equipement, PortailMediation" + 
" where DownStream.IDDownStream = Equipement.IDDownStream" +
" and PortailMediation.IDEquipement = Equipement.IDEquipement" + 
" and CDR.IDPortailMediation = PortailMediation.IDPortailMediation" +
" and DownStream.Nom = '" + downStream + 
"' and convert(varchar(10),DateCDR,103) between '" +  beginStr + "' and '" + endStr +
"' group by DownStream.IDDownStream, PortailMediation.IDNoeudOrigineCDR" +
" order by DownStream.IDDownStream, PortailMediation.IDNoeudOrigineCDR";  

查询代码如下:

public class QueryManager     
    private SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
    private String beginStr;
    private String endStr;

    /**
     * 
     * @param beginDate
     * @param endDate
     * @return 
     */
    public String getGroupedQuery(Date beginDate, Date endDate)        
        beginStr = sdf.format(beginDate);
        endStr = sdf.format(endDate);
        String groupedQuery = "select DownStream.IDDownStream as DownStream, PortailMediation.IDNoeudOrigineCDR as Node, COUNT(CDR.NomSortie) as TotalFiles," + 
                              " MIN(convert(varchar(19),DateCDR,120)) as MinDate, MAX(convert(varchar(19),DateCDR,120)) as MaxDate" + 
                              " from DownStream, CDR, Equipement, PortailMediation" + 
                              " where DownStream.IDDownStream = Equipement.IDDownStream" +
                              " and PortailMediation.IDEquipement = Equipement.IDEquipement" + 
                              " and CDR.IDPortailMediation = PortailMediation.IDPortailMediation" + 
                              " and convert(varchar(10),DateCDR,103) between '" +  beginStr + "' and '" + endStr +
                              "' group by DownStream.IDDownStream, PortailMediation.IDNoeudOrigineCDR" +
                              " order by DownStream.IDDownStream, PortailMediation.IDNoeudOrigineCDR"; 

        return groupedQuery;                     
    

    /**
     * 
     * @param beginDate
     * @param endDate
     * @param downStream
     * @return 
     */
    public String getGroupedQueryByDownStream(Date beginDate, Date endDate, String downStream) 
        beginStr = sdf.format(beginDate);
        endStr = sdf.format(endDate);
        String groupedQuery = "SELECT DownStream.IDDownStream AS DownStream, PortailMediation.IDNoeudOrigineCDR AS Node, COUNT(CDR.NomSortie) AS TotalFiles," + 
                              " MIN(convert(varchar(19),DateCDR,120)) AS MinDate, MAX(convert(varchar(19),DateCDR,120)) AS MaxDate" + 
                              " FROM DownStream, CDR, Equipement, PortailMediation" + 
                              " WHERE DownStream.IDDownStream = Equipement.IDDownStream" +
                              " AND PortailMediation.IDEquipement = Equipement.IDEquipement" + 
                              " AND CDR.IDPortailMediation = PortailMediation.IDPortailMediation" +
                              " AND DownStream.Nom = '" + downStream + 
                              "' AND convert(varchar(10),DateCDR,103) BETWEEN '" +  beginStr + "' AND '" + endStr +
                              "' GROUP BY DownStream.IDDownStream, PortailMediation.IDNoeudOrigineCDR" +
                              " ORDER BY DownStream.IDDownStream, PortailMediation.IDNoeudOrigineCDR"; 

        return groupedQuery;      
    

调用List的EJB代码:

import java.util.Date;
import java.util.List;
import javax.ejb.Stateless;
import javax.inject.Named;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import tg.moov.imereport.dao.DownStreamTotal;
import tg.moov.imereport.util.QueryManager;


@Named
@Stateless
public class DownStreamTotalEJB 

    @PersistenceContext
    private EntityManager em; 
    private QueryManager qm = new QueryManager();

    public DownStreamTotalEJB() 

    

    /**
     * Get the grouped files by period
     * @param begin
     * @param end
     * @return 
     */
    public List<DownStreamTotal> getGroupedData(Date begin, Date end)         
        Query q = em.createNativeQuery(qm.getGroupedQuery(begin, end), DownStreamTotal.class);        
        return q.getResultList();
    

    /**
     * Get the grouped files by period and by downStream
     * @param begin
     * @param end
     * @param downStream
     * @return 
     */
    public List<DownStreamTotal> getGroupedDataByDownStream(Date begin, Date end, String downStream)         
        Query q = em.createNativeQuery(qm.getGroupedQueryByDownStream(begin, end, downStream), DownStreamTotal.class);
        return q.getResultList();       
    

EJB 调用查询管理器来执行查询。

提前谢谢你!

【问题讨论】:

您如何确定 JPA 是问题所在?您是否打印或调试过集合的结果以验证集合中返回的所有 5 个 Object[] 是否与从 getResultList() 调用返回的相同? 是的,我也尝试通过迭代来获得单独的值,我注意到,我有相同的值。但是对于在数据库中执行的相同查询,我有另一个结果。 然后显示您的代码,因为字符串不足以继续。 我同意没有什么可做的,但我确实注意到您没有在 QueryManager 中使用“distinct”,也没有在 DownStreamTotalEJB 中使用 jpa 来控制它。尽管您在这两个上方显示的查询具有“不同”。那里可能有什么东西。 我尝试使用 DISTINCT,但结果是一样的。还注意到我的 EJB 包装在 Web 服务中。救命! 【参考方案1】:

最后我放弃了 JPA,我使用 JDBC 直接连接 Glassfish JNDI,它工作正常。 谢谢!

【讨论】:

【参考方案2】:

在 SQL SERVER 2008 中使用 Eclipselink 时遇到了同样的问题。

使用createNativeQuery(queryString, targetEntity) 创建查询后,似乎只能使用.getSingleResult(),而不是.getResultList()。它返回 N 次第一个实体。

恐怕目前唯一的出路是使用createNativeQuery(queryString)检索数据为List&lt;Object[]&gt;并手动进行映射。

【讨论】:

以上是关于JPA 本机查询问题的主要内容,如果未能解决你的问题,请参考以下文章

用于“选择到 outfile”的 JPA 本机查询

JPA 中的传递列表命名本机查询

jpa命名本机查询无结果

JPA 和缓存本机 SQL 查询

JPA本机sql查询映射错误?

JPA 本机查询结果集映射到具有子类的实体类