在HQL中使用SELECT DISTINCT

问题描述:

我一直在研究私人消息传递数据库模式,目前我正在尝试构建基本的数据库模式来存储和检索消息 - 没有太复杂的内容。 这是消息的实体:在HQL中使用SELECT DISTINCT

@Entity 
@Table(name="messages") 
class Message { 

    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    @Column(name="id", unique=true, nullable = false) 
    private int id; 

    @ManyToOne(cascade = CascadeType.MERGE) 
    @JoinColumn(name = "thread_id") 
    private Thread thread_id; 

    @Column(name="sent_date") 
    private Date sent_date; 

    @Column(name="message_body") 
    private String message_body; 

    @JoinColumn(name = "sender_id") 
    private User sender; 

    @JoinColumn(name = "receiver_id") 
    private User receiver; 


    // getters and setters 
} 

和线程实体仅仅是一个ID:

@Entity 
@Table(name="threads") 
class Thread { 

    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    @Column(name="id", unique=true, nullable = false) 
    private int id; 

    // getters and setters 
} 

这是叫我的查询方法:

public List<Message> getDistinctMessagesForUser(int id) { 
    return em.createQuery("SELECT m FROM Message m WHERE m.thread_id IN (SELECT DISTINCT m.thread_id FROM Message m WHERE (m.sender.id =:id OR m.receiver.id =:id)) ORDER BY m.sent_date DESC", Message.class) 
      .setParameter("id", id) 
      .getResultList(); 
} 

我使用HQL来查询数据库。我正在尝试使用SELECT DISTINCT获取每个线程的最新消息,但似乎无法使其工作。

我尝试使用这样的:

SELECT m FROM Message m WHERE (m.sender.id =:id OR m.receiver.id =:id) GROUP BY m.thread_id ORDER BY m.sent_date DESC) 

,但我一直收到此错误:

ERROR: column "message0_.id" must appear in the GROUP BY clause or be used in an aggregate function 

我也试图在这个link所示的方法,但错误是因为这样的事实结果该查询有e和m。

我试过的每一个其他查询都返回了所有的消息(而不是独特的),或者抛出了我上面描述的错误。我不想使用CriteriaAPI,因为我读的是它比HQL慢,而我拥有的其他代码是用HQL编写的,我打算坚持一种方法。 我错过了什么?

+0

尝试'SELECT m,m.thread_Id FROM Message m WHERE(m.sender.id =:id or m.receiver.id =:id)GROUP BY m.thread_id ORDER BY m.sent_date DESC)' – fg78nc

+0

它给出了我这个错误:'java.lang.IllegalArgumentException:无法创建TypedQuery的查询与多个返回使用请求的结果类型[消息]' – Aria

+0

你在DISTINCT上得到什么样的错误?请发布生成的SQL。 – fg78nc

DISTINCT在这种情况下工作应该工作。问题出在您的逻辑上,因为您在子查询中检索不同的thread实体,然后您的外部查询根据子查询的结果集检索message,但您没有以这种方式获得唯一的'消息'实体,因为每个message实体都可以与几个甚至唯一的thread相关联。

我建议改变查询通过获得的最早消息(通过message PK(或ID))中通过与每一个独特的thread相关

List<MyMessage> myMes = em.createQuery(
       "SELECT m from MyMessage m where m.id " 
       + "in (select min(m2.id) from MyMessage m2 group by m2.thread_id) " 
       + "and (m.sender.id =:id OR m.receiver.id =:id)", MyMessage.class) 
       .setParameter("id", 1L) 

在这里,我们第一次(也是唯一的第一个)检索message实体min()