Maison > Java > Agréger les sous-entités dans les résultats de requête à l'aide de JPA et QueryDSL

Agréger les sous-entités dans les résultats de requête à l'aide de JPA et QueryDSL

PHPz
Libérer: 2024-02-09 21:00:20
avant
776 Les gens l'ont consulté

L'éditeur PHP Baicao a publié un article sur l'utilisation de JPA et QueryDSL pour agréger des sous-entités dans les résultats de requête. Dans cet article, nous verrons comment gérer les résultats des requêtes des sous-entités lors de l'exécution de requêtes agrégées à l'aide de JPA et QueryDSL. En étudiant cet article, les lecteurs seront en mesure de comprendre comment implémenter des requêtes agrégées sur des sous-entités via JPA et QueryDSL, et d'obtenir des résultats de requête précis et efficaces. Que vous soyez un développeur débutant ou expérimenté, cet article vous fournira des connaissances et des conseils précieux pour vous aider à mieux utiliser JPA et QueryDSL pour gérer les sous-entités dans les requêtes agrégées dans des projets réels.

Contenu de la question

Je développe une application Java utilisant jpa et querydsl et je suis confronté au défi de la requête relationnelle un-à-plusieurs. J'ai trois entités : Articles, Commentaires et Réactions. Chaque message (un) peut avoir plusieurs commentaires et réactions (plusieurs). J'ai besoin d'obtenir chaque article et ses commentaires et réactions regroupés.

Voici mon approche actuelle :

public page<articledetail> findarticles(pagerequest pagerequest, user currentuser) {
    var articles = new jpaqueryfactory(entitymanager)
            .select(projections.constructor(articledetail.class,
                    article.id,
                    projections.constructor(userdetail.class,
                            user.id,
                            user.name,
                            user.username,
                            user.email,
                            user.profilepicture,
                            user.level,
                            user.position),
                    article.content,
                    article.type,
                    projections.list(projections.constructor(commentdetail.class,
                            comment.user.id,
                            comment.article.id,
                            comment.text,
                            comment.timestamp).skipnulls()).skipnulls(),
                    projections.list(projections.constructor(reactiondetail.class,
                            reaction.user.id,
                            reaction.type).skipnulls()).skipnulls(),
                    article.commentcount,
                    article.datecreated,
                    article.datelastmodified
                ))
                .from(article)
                .innerjoin(article.user, user)
                .leftjoin(article.comments, comment).on(comment.isactive.istrue())
                .leftjoin(article.reactions, reaction)
                .where(article.isactive.istrue(),
                        user.status.eq(status.active),
                        article.user.in(currentuser.getfollowing())
                                .or(article.user.eq(currentuser)))
                .offset(pagerequest.getoffset())
                .limit(pagerequest.getpagesize())
                .orderby(article.id.asc())
                .fetch();

    return new pageimpl<>(articles, pagerequest, articles.size());
}
Copier après la connexion

Entité :

@Entity
public class Article {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_id")
    private User user;

    @OneToMany(mappedBy = "article")
    private Set<Comment> comments;

    @OneToMany(mappedBy = "article")
    private Set<Reaction> reactions;

    // Other fields like content, type, etc.
}

@Entity
public class Comment {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "article_id")
    private Article article;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_id")
    private User user;

    // Other fields like text, timestamp, etc.
}

@Entity
public class Reaction {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "article_id")
    private Article article;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_id")
    private User user;

    // Other fields like type, etc.
}

@Entity
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @OneToMany(mappedBy = "user")
    private Set<Article> articles;

    // Other user fields like name, username, email, etc.
}
Copier après la connexion

Cette méthode doit renvoyer une page d'objets articledetail, chacun contenant les détails de l'article, l'auteur, les commentaires et les réactions. Cependant, le problème auquel je suis confronté est que les commentaires et réactions ne sont pas correctement regroupés sous leurs articles respectifs. Chaque instance de articledetail doit contenir une liste de commentdetail et de réactiondetail , mais elles sont renvoyées sous forme d'entrées distinctes.

Existe-t-il un moyen de construire cette requête pour regrouper correctement les commentaires et réactions sous leurs articles respectifs ? Ou doit-il être traité par programme après avoir obtenu les données ?

Toutes suggestions ou alternatives seraient grandement appréciées !

Solution de contournement

La solution que j'ai mise en œuvre implique un processus de requête en deux étapes utilisant querydsl :

Tout d'abord, je récupère les identifiants des articles qui répondent à certains critères :

var articleids = jpaqueryfactory
        .select(article.id)
        .from(article)
        // conditions and joins
        .fetch();
Copier après la connexion
var articles = jpaQueryFactory
        .select(article)
        .from(article)
        // Joins for comments and reactions
        .where(article.id.in(articleIds))
        .transform(groupBy(article.id).list(
            Projections.constructor(ArticleDetail.class,
                // Projection fields
            )));

return new PageImpl<>(articles, pageRequest, articles.size());
Copier après la connexion

Aspects clés de la solution : Utilisez un processus de requête en deux étapes pour obtenir d’abord l’identifiant de l’article, puis récupérez l’article correspondant en agrégeant les données. L'utilisation de groupby().list() ainsi que de projections.constructor() est cruciale pour regrouper correctement les commentaires et les réactions sous chaque publication. Cette approche résout efficacement le problème du regroupement des commentaires et des réactions sous leurs articles respectifs tout en garantissant une acquisition et une pagination efficaces des données.

J'espère que cette explication détaillée aidera d'autres personnes confrontées à des situations similaires. Les commentaires ou suggestions pour une optimisation ultérieure sont toujours les bienvenus !

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:stackoverflow.com
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal