2010-04-27 18 views
6

Tengo dificultades para representar esta consulta (que funciona en la base de datos directamente) como consulta de criterios en Hibernate (versión 3.2.5):Consulta de criterios de Hibernate usando proyección Max() en campo clave y grupo por clave primaria externa

SELECT s.* 
    FROM ftp_status s 
WHERE (s.datetime,s.connectionid) IN (SELECT MAX(f.datetime), 
               f.connectionid 
             FROM ftp_status f 
             GROUP BY f.connectionid); 

hasta ahora esto es lo que he llegado con eso no funciona, y lanza un mensaje de error could not resolve property: datetime of: common.entity.FtpStatus:

Criteria crit = s.createCriteria(FtpStatus.class); 
crit = crit.createAlias("connections", "c"); 
crit = crit.createAlias("id", "f"); 
ProjectionList proj = Projections.projectionList(); 
proj = proj.add(Projections.max("f.datetime")); 
proj = proj.add(Projections.groupProperty("c.connectionid")); 
crit = crit.setProjection(proj); 
List<FtpStatus> dtlList = crit.list(); 

Aquí está la configuración de referencia relevante que Netbeans 6.8 genera directamente de la base de datos :

FtpStatus.hbm.xml -

<hibernate-mapping> 
    <class name="common.entity.FtpStatus" table="ftp_status" catalog="common"> 
     <composite-id name="id" class="common.entity.FtpStatusId"> 
      <key-property name="siteid" type="int"> 
       <column name="siteid" /> 
      </key-property> 
      <key-property name="connectionid" type="int"> 
       <column name="connectionid" /> 
      </key-property> 
      <key-property name="datetime" type="timestamp"> 
       <column name="datetime" length="19" /> 
      </key-property> 
     </composite-id> 
     <many-to-one name="connections" class="common.entity.Connections" update="false" insert="false" fetch="select"> 
      <column name="connectionid" not-null="true" /> 
     </many-to-one> 
     <many-to-one name="sites" class="common.entity.Sites" update="false" insert="false" fetch="select"> 
      <column name="siteid" not-null="true" /> 
     </many-to-one> 
     <property name="upInd" type="boolean"> 
      <column name="up_ind" not-null="true" /> 
     </property> 
     <property name="lastMessage" type="string"> 
      <column name="last_message" length="65535" not-null="true" /> 
     </property> 
    </class> 
</hibernate-mapping> 

Connections.hbm.xml -

<hibernate-mapping> 
    <class name="common.entity.Connections" table="connections" catalog="common"> 
     <id name="connectionid" type="java.lang.Integer"> 
      <column name="connectionid" /> 
      <generator class="identity" /> 
     </id> 
     <property name="ip" type="string"> 
      <column name="ip" length="15" not-null="true" /> 
     </property> 
     <property name="port" type="int"> 
      <column name="port" not-null="true" /> 
     </property> 
     <property name="user" type="string"> 
      <column name="user" length="8" not-null="true" /> 
     </property> 
     <property name="password" type="string"> 
      <column name="password" length="50" not-null="true" /> 
     </property> 
     <set name="ftpStatuses" inverse="true"> 
      <key> 
       <column name="connectionid" not-null="true" /> 
      </key> 
      <one-to-many class="common.entity.FtpStatus" /> 
     </set> 
    </class> 
</hibernate-mapping> 

Sé que me falta algo, pero mi googling en hibernación no ha revelado todavía. Alternativamente, una consulta SQL directamente usando s.createSQLQuery() o s.createQuery() también es aceptable, pero he tenido aún menos éxito al escribir esa ...

Respuesta

23

El Criteria que ha suministrado parece generar solo la parte de consulta interna. Puede combinar la consulta interna, p. mediante el uso de DetachedCriteria:

DetachedCriteria maxDateQuery = DetachedCriteria.forClass(FtpStatus.class); 
ProjectionList proj = Projections.projectionList(); 
proj.add(Projections.max("datetime")); 
proj.add(Projections.groupProperty("connectionid")); 
maxDateQuery.setProjection(proj); 

Criteria crit = s.createCriteria(FtpStatus.class); 
crit.add(Subqueries.propertiesEq(new String[] {"datetime", "connectionid"}, maxDateQuery)); 

List<FtpStatus> dtlList = crit.list(); 

Nota que el apoyo a las subconsultas de varias columnas no se implementa hasta que en Hibernate 4.0.0.CR5 (HHH-6766). Como lo que se refiere a consultas SQL nativas, Hibernate's createSQLString debería funcionar inmediatamente con la cadena de consulta que especificó o con las entidades involucradas en la consulta agregada, si quiere tener nombres de columna explícitos en la consulta resultante.

String queryString = "SELECT {status.*}" 
        + " FROM ftp_status status" 
        + " WHERE (datetime, connectionid) IN (" 
        + " SELECT MAX(datetime), connectionid" 
        + "  FROM ftp_status" 
        + "  GROUP BY connectionid" 
        + " )"; 

SQLQuery query = s.createSQLQuery(queryString).addEntity("status", FtpStatus.class); 

List<FtpStatus> dtlList = query.list(); 
+1

simplemente cambie las propiedadesEq a propertiesIn, funciona bien. –

Cuestiones relacionadas