【问题标题】:How to join multiple queryDSL tables如何连接多个 queryDSL 表
【发布时间】:2018-05-21 22:06:25
【问题描述】:

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

我有这些表:

  • 账户表:accountId (PK) |电子邮件 |密码

  • account_profile 表:accountId (PK)(fk to account) |昵称

  • 社区表:articleId (PK) | accountId (fk to account) |标题 |内容

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

select r from community r join r.account.profile a where a.nickname = :nickname

我有实体元模型 - 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();

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

编辑:附加实体信息

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

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;

}

Community.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;
}

编辑:问题已解决

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

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

【问题讨论】:

  • 请为实体发布代码。
  • @Mogsdad 感谢您重新安排我的问题 :)
  • @lzagkaretos 更新了我的实体信息谢谢:)
  • 查询select r from article r join r.account.profile a where a.nickname = :nickname 是否正确?我的意思是,您没有提供Article 实体的代码以及它与其他实体的连接方式。
  • 很抱歉文章错了,“从社区中选择 r ...”是对的,我会编辑这篇文章。

标签: spring jpa spring-data dsl querydsl


【解决方案1】:

我找到了一种解决方案

QEntity qEntity1 = new QEntity("qEntity1");
QEntity qEntity2 = new QEntity("qEntity2");

所以在查询时你可以使用

new JPAQueryFactory(entityManager).from(qSampleBO)
    .innerJoin(qEntity1).on(qEntity1.id.eq(qSampleBO.address.id))
    .innerJoin(qEntity2).on(qEntity2.id.eq(qSampleBO.secondary_address.id))
    ...

【讨论】:

    【解决方案2】:

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

    首先是界面:

    @NoRepositoryBean
    public interface ExtendedQueryDslJpaRepository<T, ID extends Serializable> 
            extends JpaRepository<T, ID>, QueryDslPredicateExecutor<T> {
    
        <T1> Page<T1> findAll(JPQLQuery jpqlQuery, Pageable pageable);
    }
    

    然后是实现:

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

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

    @Configuration
    @EnableJpaRepositories(basePackageClasses = ..., repositoryBaseClass = ExtendedQueryDslJpaRepositoryImpl.class)
    

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

    @Repository
    public interface CommunityRepository extends ExtendedQueryDslJpaRepository<Community, Long> {
    }
    

    那么,你可以试试下面的代码:

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

    希望对您有所帮助。

    【讨论】:

    • 谢谢你,我能问你我在哪里提到这个问题吗?我的意思是谷歌上没有参考链接
    • 它对你有用吗?有关使用 QueryDSL 的文档存在 here
    • 其实我在编辑我的帖子后还没有尝试。我正要睡觉。在我的国家,时间是凌晨 4 点
    • QueryDslJpaRepository 现已弃用,有没有办法在不覆盖整个 JpaRepository 的情况下为 QuerydslPredicateExecutor 提供自定义实现?
    • @ManolisPap 在过去的几年里我没有使用过QueryDsl,所以我不知道是否存在更好(更直接的方法)。
    猜你喜欢
    • 2023-04-01
    • 2018-01-31
    • 1970-01-01
    • 1970-01-01
    • 2012-06-27
    • 1970-01-01
    • 2014-07-13
    相关资源
    最近更新 更多