2010-04-27 3 views
6

Ho difficoltà a rappresentare questa query (che funziona direttamente sul database) come query di criteri in Hibernate (versione 3.2.5):Interroga la query di criteri utilizzando la proiezione Max() sul campo chiave e il gruppo per chiave primaria esterna

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); 

finora questo è ciò che mi è venuta in mente che non funziona, e lancia un messaggio di errore di 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(); 

Ecco la configurazione di riferimento rilevante che Netbeans 6.8 generato direttamente dal database :

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> 

So che mi manca qualcosa, ma il mio googling su di ibernazione non è stato ancora rivelato. In alternativa, una query SQL utilizzando direttamente s.createSQLQuery() o s.createQuery() è anche accettabile, ma ho avuto ancora meno successo per iscritto che una .....

risposta

23

Il Criteria si forniti sembra generare solo la parte interna query. Puoi combinare la query interna, ad es. utilizzando 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(); 

noti che il supporto per la sottoquery a più colonne non è implementata fino a quando nel Hibernate 4.0.0.CR5 (HHH-6766).

Per quanto riguarda le query SQL native, lo createSQLString di Hibernate dovrebbe funzionare immediatamente con la stringa di query specificata o con le entità coinvolte nella query aggiunta, se si desidera avere nomi di colonna espliciti nella query risultante.

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

è sufficiente modificare proprietàEq su propertiesIn, funziona correttamente. –