2017-07-26 2 views
2

Je me suis intéressé aux schémas de base de données de messagerie privée et j'essaie actuellement de créer un schéma de base de données db pour stocker et récupérer des messages - rien de trop complexe. Ceci est l'entité du message:Utilisation de SELECT DISTINCT dans HQL

@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 
} 

et l'entité de discussion est juste un 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 
} 

c'est la méthode qui appelle ma requête:

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

J'utilise HQL interroger le db. J'essaie d'obtenir les messages les plus récents pour chaque thread en utilisant un SELECT DISTINCT mais je n'arrive pas à le faire fonctionner.

J'ai essayé d'utiliser ceci:

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) 

mais je continué à obtenir cette erreur:

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

J'ai aussi essayé la méthode indiquée dans cette link mais l'erreur est en raison du fait que la requête avait e et m.

Chaque autre requête que j'ai essayé a renvoyé tous les messages (au lieu de distinct) ou a lancé l'erreur que j'ai décrite ci-dessus. Je ne veux pas utiliser CriteriaAPI en lisant que c'est plus lent que HQL, et l'autre code que j'ai est écrit en HQL et je prévois de m'en tenir à une méthode. Qu'est-ce qui me manque?

+0

Essayez 'SELECT m, m.thread_Id FROM Message m WHERE (m.sender.id =: id OU m.receiver.id =: id) GROUPE BY m.thread_id ORDER BY m.sent_date DESC)' – fg78nc

+0

moi cette erreur: 'java.lang.IllegalArgumentException: Impossible de créer TypedQuery pour la requête avec plus d'un retour en utilisant le type de résultat demandé [Message]' – Aria

+0

Quel genre d'erreur obtenez-vous sur DISTINCT? Veuillez poster des messages SQL générés. – fg78nc

Répondre

0

DISTINCT fonctionne dans ce cas fonctionne à elle devrait fonctionner. Le problème réside dans votre logique, lorsque vous récupérez des entités thread distinctes dans la sous-requête, puis votre requête externe récupère message en fonction du jeu de résultats de la sous-requête, mais vous n'obtenez pas les entités 'message' de cette manière, car chaque entité message peut être associé à plusieurs même unique thread s.

Je suggère de modifier la requête pour

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) 

Ici, nous récupérons d'abord (et seulement le premier) message entité associée à chaque thread unique en faire passer le message au plus tôt (par PK (ou id) de message) via min().