【问题标题】:Hibernate Criteria -- return records where column is distinctHibernate Criteria -- 返回列不同的记录
【发布时间】:2012-08-10 05:35:36
【问题描述】:

示例数据库表:

  1. ID = 1,msgFrom = 'Hello',foobar = 'meh'
  2. ID = 2,msgFrom = '再见',foobar = 'cmets'
  3. ID = 3,msgFrom = 'Hello',foobar = 'response'

所需输出示例(由休眠查询生成):

  1. ID = 1,msgFrom = 'Hello',foobar = 'meh'
  2. ID = 2,msgFrom = '再见',foobar = 'cmets'

在上面的示例中,第三条记录将从结果中排除,因为 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/

【问题讨论】:

  • 可能是stackoverflow.com/questions/5196243/… 会有帮助吗?
  • @aishwarya 我已经看到了。那篇文章结合了两列并使其与众不同。不是我想要做的。
  • @KyleM,当然,我的意思是你试过设置投影Projections.distinct(Projections.property("id.msgFrom")) 吗?
  • id 是在哪里声明的?这个怎么样......如果你知道你想让我尝试什么,发布一个答案,我会尝试你给我的确切语法。
  • @aishwarya 这不是因为我很懒惰。我不明白你为什么要暗示你是什么。在您的示例中,“id”是什么?是在哪里宣布的?如果您发布回复并澄清您建议我尝试的内容,以及为什么...,这可能会更容易

标签: java hibernate criteria-api


【解决方案1】:

请试试这个并告诉我

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

【讨论】:

  • 谢谢。我会在一天结束之前尝试这个,让你知道它是否有效。感谢您的回复。
  • 对不起,我没有。由于汽车问题,我提前下班了,但我一定会尽快检查并奖励您我能获得的任何积分(赏金和/或投票)。谢谢。
  • 我使用上面的代码,但我想返回不同的聊天消息,其中 userid = someValue 并且只返回不同的和最后一个..你能告诉我我是怎么做到的吗?
【解决方案2】:

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

SELECT DISTINCT on one column

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

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

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

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

但您必须接受丢弃所有其他列。

最后,我经常只是在代码中将其用作后查询过滤器。另一种选择是创建另一个表,例如 CurrentMessage,其中包括 msgFrom 作为键的一部分。需要做更多的工作来保持此表的最新状态(每次向 Message 表添加一行时都需要更新一行),但查询会容易得多。

【讨论】:

  • 将其作为“后查询过滤器”是我不想做的,因为我必须在应用服务器上这样做。查看我的编辑..
  • 您的查询还有其他条件吗?正如 James 所说,就数据库而言,返回记录 1 与 3 完全是任意的,这就是他建议在应用程序端执行此操作的原因。
  • @jeff 我知道这是任意的,但对我的用例来说并不重要。 :(
【解决方案3】:
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();

【讨论】:

  • 谢谢詹姆斯,还没有尝试过,因为我今天在不同的设施。如果我有任何问题,我会在今天晚些时候或明天早上通知您。
  • 詹姆斯,不幸的是,这对我不起作用。即使只有 10 个不同的“msgFrom”值,它也检索了超过 10,000 条记录。这在过去对你有用吗..?
  • 我认为这个例子行得通,我必须承认。因此,我得出的结论是,您必须使用直接 HQL 来解决这个问题,并避免使用 Criteria API。似乎很多人在使用 Criteria 和 distinct 时遇到了问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-11-16
  • 1970-01-01
  • 2021-01-17
  • 2013-06-25
  • 2013-04-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多