Hibernate criteria query using Max() projection on key field and group by foreign primary key

∥☆過路亽.° 提交于 2019-12-30 06:32:08

问题


I'm having difficulty representing this query (which works on the database directly) as a criteria query in Hibernate (version 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);

so far this is what I've come up with that doesn't work, and throws a could not resolve property: datetime of: common.entity.FtpStatus error message:

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

Here's the relevant reference configuration that Netbeans 6.8 generated directly from the 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>

I know I'm missing something, but my googling on hibernate hasn't revealed it yet. Alternatively a SQL query directly using s.createSQLQuery() or s.createQuery() is also acceptable, but I've had even less success writing that one.....


回答1:


The Criteria you supplied seems to generate only the inner query part. You can combine the inner query e.g. by using 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();

Note that support for multicolumn subqueries is not implemented until in Hibernate 4.0.0.CR5 (HHH-6766).

As what comes to native SQL queries, Hibernate's createSQLString should work straight away with the query string you specified, or with the entities involved in the query added, if one want's to have explicit column names in the resulting query.

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


来源:https://stackoverflow.com/questions/2723803/hibernate-criteria-query-using-max-projection-on-key-field-and-group-by-foreig

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!