Hibernate Criteria – 返回列不同的记录

示例数据库表:

  1. ID = 1,msgFrom =’你好’,foobar =’meh’
  2. ID = 2,msgFrom =’再见’,foobar =’评论’
  3. ID = 3,msgFrom =’Hello’,foobar =’response’

示例所需的输出(由hibernate查询生成):

  1. ID = 1,msgFrom =’你好’,foobar =’meh’
  2. ID = 2,msgFrom =’再见’,foobar =’评论’

在上面的示例中,第三条记录将从结果中排除,因为msgFrom列是相同的。 假设Java / Hibernate类叫做Message。 我希望结果作为Message对象列表(或者可以转换为Message的对象)返回。 我希望尽可能使用Criteria API。 我在SO上看到了这个例子,看起来很相似,但我还是无法正确实现它。

select e from Message e where e.msgFrom IN (select distinct m.msgFrom from Message m WHERE m.msgTo = ? AND m.msgCheck = 0"); 

我这样做的原因是要对数据库上的不同记录进行过滤,所以我对我必须在应用程序服务器上过滤任何内容的答案不感兴趣。

编辑:文章基本上显示了我想要做的事情。 http://oscarvalles.wordpress.com/2008/01/28/sql-distinct-on-one-column-only/

请试试这个让我知道

 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 list = criteria.list(); for(Message message:list){ System.out.println(message.getId() +"-------" +message.getMessageFrom() +"-----" +message.getFoobar()); } 

这个查询的难度本身并不是Hibernate,而是一般的关系模型。 在这个例子中,你说你期望第1行和第2行,但为什么你不能轻易地期望第2行和第3行? 由于它们在msgFrom字段中具有相同的值,因此返回第1行或第3行将是一个任意的决定。 数据库不会像这样做出任意决定。 这就是为什么必须将distinct应用于整个选择列列表,而不是子集。 有特定于数据库的方法来获取第一个匹配的行。 例如,看看

在一列上选择DISTINCT

有时会有一个日期列,您可以使用它来决定返回哪些匹配的行,但同样的查询有点复杂:

如何通过SQL中的另一列选择MAX(列值),DISTINCT的行?

获取具有列的最大值的行

如果你不关心任何其他列,你可以使用一个简单的distinct ,结合Hibernate的构造函数语法(未经测试):

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

但你必须接受扔掉所有其他列。

最后,我经常最终只是在代码中执行此操作作为后查询filter。 另一种选择是创建另一个表,比如说CurrentMessage,它包含msgFrom作为键的一部分。 将更多工作保持此表是最新的(每次向Message表添加行时都需要更新行)但查询将更容易。

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