如何联接多个queryDSL表

2 dsl spring jpa querydsl spring-data

我有一些表,我想使用queryDSL联接获得结果,但是没有找到关于使用queryDSL的多个联接的任何示例。

我有这些表:

  • 帐户表:accountId(PK)| 电邮| 密码

  • account_profile表:accountId(PK)(fk到帐户)| 昵称

  • 社区表:articleId(PK)| accountId(fk到帐户)| 标题| 内容

现在我想在JPQL下面是queryDSL代码

select r from community r join r.account.profile a where a.nickname = :nickname
Run Code Online (Sandbox Code Playgroud)

我有实体元模型-QAccount,QAccountProfile,QCommunity

另外,我必须通过分页来获取结果,因此查询应与pageable对象一起调用。

这是我的工作尚未完成。

JPAQuery</*What generic type expected?*/> query = new JPAQuery</*???*/>(entityManager);
Predicate predicate = query.from(QCommunity.community).join(/*join directly accountProfile? or account? is it QEntity or real entity?*/);

// where should I place nickname matching condition ?


...

list = (repository.findAll(predicate, pageable)).getContent();
Run Code Online (Sandbox Code Playgroud)

昵称匹配条件应放在哪里?

编辑:附加实体信息

Account.java

@Entity
@Table(name="account", uniqueConstraints={
    @UniqueConstraint(columnNames="account_seq"),
    @UniqueConstraint(columnNames="email")
})
@DynamicInsert
@DynamicUpdate
@Data
@EqualsAndHashCode
@ToString(includeFieldNames=true)
@RequiredArgsConstructor(staticName="of")
@NoArgsConstructor
public class Account implements Serializable{

    private static final long serialVersionUID = 1L;

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

    @Column(name="email", nullable=false, unique=true)
    @NonNull
    private String email;

    @NonNull
    private String password;

    @OneToOne(cascade=CascadeType.ALL, mappedBy="account")
    private AccountProfile profile;

    @OneToOne(cascade=CascadeType.ALL, mappedBy="account")
    private AccountSecurity security;
}
Run Code Online (Sandbox Code Playgroud)

AccountProfile.java

@Entity
@Table(name="account_profile", uniqueConstraints={
    @UniqueConstraint(columnNames={"account_seq"}),
    @UniqueConstraint(columnNames={"nickname"})
})
@DynamicInsert
@DynamicUpdate
@Data
@EqualsAndHashCode
@ToString(includeFieldNames=true)
@RequiredArgsConstructor(staticName="of")
@NoArgsConstructor
public class AccountProfile implements Serializable{

    private static final long serialVersionUID = 1L;

    @Id
    @OneToOne(cascade=CascadeType.ALL)
    @JoinColumn(name="account_seq", referencedColumnName="account_seq")
    private Account account;

    @Column(name="nickname", nullable=false)
    @NonNull
    private String nickname;

}
Run Code Online (Sandbox Code Playgroud)

社区.java

@Entity
@Table(name="community", uniqueConstraints = {
        @UniqueConstraint(columnNames="article_seq")
})
@DynamicInsert
@DynamicUpdate
@Data
@NoArgsConstructor
@EqualsAndHashCode
@ToString(includeFieldNames=true)
public class Community {

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

    @ManyToOne(cascade=CascadeType.ALL)
    @JoinColumn(name="account_seq", referencedColumnName="account_seq")
    private Account account;

    @Column(name="title", nullable=false)
    private String title;

    @Column(name="content", nullable=false)
    private String content;

    @Temporal(TemporalType.TIMESTAMP)
    @Column(name="reg_dt")
    private Date date;

    @Column(name="read_cnt", nullable=false)
    private int readCount;

    @Column(name="attach_url")
    private String attachUrl;

    @Column(name="attach_filename")
    private String attachFileName;

    @OneToMany(cascade=CascadeType.ALL, mappedBy="article")
    private Set<CommunityReply> replies;
}
Run Code Online (Sandbox Code Playgroud)

编辑:解决的问题

为了帮助像我这样面临问题的其他人,我将发布我的工作代码。该代码将搜索具有特定昵称匹配的所有社区文章。

@PersistenceContext
    private EntityManager entityManager;


    private List<Community> getList(int pageNo, String keyword, int rowsOnPage){

        int offset = (pageNo -1) * rowsOnPage;
        int limit = rowsOnPage;

        JPAQuery<Community> query = new JPAQuery<Community>(entityManager);

        QCommunity qCommunity = QCommunity.community;
        QAccount qAccount = QAccount.account;
        QAccountProfile qAccountProfile = QAccountProfile.accountProfile;

        return query
            .from(qCommunity)
            .innerJoin(qCommunity.account ,qAccount)
            .innerJoin(qAccount.profile, qAccountProfile)
            .where(qAccountProfile.nickname.like("%"+keyword+"%"))
            .orderBy(qCommunity.articleId.desc())
            .offset(offset)
            .limit(limit)
        .fetch();
    }
Run Code Online (Sandbox Code Playgroud)

lza*_*tos 8

首先,为QueryDSL查询声明一个自定义的扩展基础存储库类。

首先界面:

@NoRepositoryBean
public interface ExtendedQueryDslJpaRepository<T, ID extends Serializable> 
        extends JpaRepository<T, ID>, QueryDslPredicateExecutor<T> {

    <T1> Page<T1> findAll(JPQLQuery jpqlQuery, Pageable pageable);
}
Run Code Online (Sandbox Code Playgroud)

然后执行:

public class ExtendedQueryDslJpaRepositoryImpl<T, ID extends Serializable>
        extends QueryDslJpaRepository<T, ID> implements ExtendedQueryDslJpaRepository<T, ID> {

    private static final EntityPathResolver DEFAULT_ENTITY_PATH_RESOLVER = SimpleEntityPathResolver.INSTANCE;

    private final EntityPath<T> path;
    private final PathBuilder<T> builder;
    private final Querydsl querydsl;

    private EntityManager entityManager;

    public ExtendedQueryDslJpaRepositoryImpl(JpaEntityInformation<T, ID> entityInformation, EntityManager entityManager) {
        this(entityInformation, entityManager, DEFAULT_ENTITY_PATH_RESOLVER);
    }

    public ExtendedQueryDslJpaRepositoryImpl(JpaEntityInformation<T, ID> entityInformation, 
           EntityManager entityManager, EntityPathResolver resolver) {

        super(entityInformation, entityManager);
        this.path = resolver.createPath(entityInformation.getJavaType());
        this.builder = new PathBuilder(this.path.getType(), this.path.getMetadata());
        this.querydsl = new Querydsl(entityManager, this.builder);
        this.entityManager = entityManager;
    }

    @Override
    public <T1> Page<T1> findAll(JPQLQuery jpqlQuery, Pageable pageable) {

        // Count query
        final JPQLQuery<?> countQuery = jpqlQuery;

        // Apply pagination
        JPQLQuery<T1> query = querydsl.applyPagination(pageable, jpqlQuery);

        // Run query
        return PageableExecutionUtils.getPage(query.fetch(), pageable, countQuery::fetchCount);
    }
}
Run Code Online (Sandbox Code Playgroud)

将新类定义为类中基础库和存储库的基础@Configuration

@Configuration
@EnableJpaRepositories(basePackageClasses = ..., repositoryBaseClass = ExtendedQueryDslJpaRepositoryImpl.class)
Run Code Online (Sandbox Code Playgroud)

然后,您的存储库应该从新接口扩展(当然,它是JpaRepository的扩展):

@Repository
public interface CommunityRepository extends ExtendedQueryDslJpaRepository<Community, Long> {
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以尝试以下代码:

String nickname = "nick";

QAccount account = QAccount.account;
QAccountProfile accountProfile = QAccountProfile.accountProfile;
QCommunity community = QCommunity.community;

JPQLQuery query = new JPAQuery(entityManager);

BooleanBuilder predicate = new BooleanBuilder();
predicate.and(accountProfile.nickname.eq(nickname));

// select r from community r join r.account.profile a where a.nickname = :nickname
query.from(community)
     .join(community.account, account)
     .join(account.accountProfile, accountProfile)
     .where(predicate);

repository.findAll(query, pageable);
Run Code Online (Sandbox Code Playgroud)

希望能有所帮助。

  • “QueryDslJpaRepository”现已弃用,是否有一种方法可以为“QuerydslPredicateExecutor”提供自定义实现,而无需覆盖整个“JpaRepository”? (2认同)