Hibernate Criteria — return records where column is distinct

穿精又带淫゛_ 提交于 2019-12-05 12:52:17
Java P

Please try this and let me know

DetachedCriteria msgFromCriteria = DetachedCriteria.forClass(Message.class);
ProjectionList properties = Projections.projectionList();
properties.add(Projections.groupProperty("messageFrom"));
properties.add(Projections.min("id"),"id");
msgFromCriteria.setProjection(properties);

Criteria criteria = s.createCriteria(Message.class);
criteria.add(Subqueries.propertiesIn(new String[]{"messageFrom","id"}, 
    msgFromCriteria));
List<Message> list = criteria.list();

for(Message message:list){
    System.out.println(message.getId()
        +"-------"
        +message.getMessageFrom()
        +"-----"
        +message.getFoobar());
}
James Scriven

The difficulty with this query is not so much with Hibernate, per se, but with the relational model in general. In the example, you say you expect rows 1 and 2, but why wouldn't you just as easily expect rows 2 and 3? It would be an arbitrary decision whether to return row 1 or row 3 since they both have the same value in the msgFrom field. Databases won't make arbitrary decisions like this. That's why distinct must be applied to the entire list of select columns, not a subset. There are database-specific ways of grabbing the first matching rows. For example, have a look at

SELECT DISTINCT on one column

Sometimes there will be a date column that you can use to decide which of the matching rows to return, but again the queries get somewhat complex:

How can I SELECT rows with MAX(Column value), DISTINCT by another column in SQL?

Fetch the row which has the Max value for a column

If you don't care about any of the other columns, you can just use a simple distinct, combined with Hibernate's constructor syntax (not tested):

select new Message(msgFrom) from (select distinct msgFrom from Message)

but you have to accept throwing away all the other columns.

In the end, I often end up just doing this in code as a post query filter. Another option is to create a another table, say CurrentMessage, that includes msgFrom as part of the key. There will be more work in keeping this table up to date (you need to update a row everytime you add a row to the Message table) but querying will be much easier.

DetachedCriteria msgFromCriteria = DetachedCriteria.forClass(Message.class);
msgFromCriteria.setProjection(Projections.distinct(Projections.property("msgFrom")));
....
Criteria criteria = getSession().createCriteria(Message.class);
criteria.add(Subqueries.propertyIn("msgFrom", msgFromCriteria));
criteria.list();
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!