Criteri Hibernate Query utilizzando max) sporgenza (sul campo chiave e raggruppa per chiave primaria estera
-
01-10-2019 - |
Domanda
Sto avendo difficoltà a rappresentare questa domanda (che funziona sulla base di dati direttamente) come una query criteri di Hibernate (versione 3.2.5):
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 è quello che mi è venuta in mente che non funziona, e lancia un messaggio di errore 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>
Lo so che mi manca qualcosa, ma il mio googling in ibernazione non ha rivelato ancora. In alternativa, una query SQL utilizzando direttamente s.createSQLQuery()
o s.createQuery()
è anche accettabile, ma ho avuto la scrittura ancora meno successo che uno .....
Soluzione
Il Criteria
che hai fornito sembra generare solo la parte interna query. È possibile combinare la query interna per esempio 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();
Si noti che il supporto per sottoquery a più colonne non è implementata fino a Hibernate 4.0.0.CR5 (HHH -6766) .
Come quello che tratta di query SQL nativo, createSQLString
di Hibernate dovrebbe lavorare subito con la stringa di query specificata, o con gli enti coinvolti nella query aggiunto, se si voglia di di avere i 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();