java - 如何在 JPAQuery 中使用 INNER JOIN?

标签 java spring-data querydsl predicate

我准确地说,我是一名法国学生,正在学习 Java 开发人员一年级。 而且我很确定我的问题标题对于我想要做的事情来说甚至不正确。那么希望下面的解释会更清楚一些!

我正在使用 Spring Boot、Spring security、Hibernate、Spring Data、Spring MVC 和 Thymeleaf 开发一个小型多模块应用程序。

这里是my repo

我目前正在研究一种处理多条件请求的方法。 我正在使用 Querydsl。

这是涉及的域部分:

母实体

@Entity
@Table(name="element")
@Inheritance(strategy = InheritanceType.JOINED)
@Getter
@Setter
@NoArgsConstructor
@ToString
@EqualsAndHashCode
public abstract class Element {

//----------ATTRIBUTES----------

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;
    @NotNull
    @Size(min=4,max=50)
    private String name;
    private LocalDateTime createDate;
    private LocalDateTime updateDate;
    @OneToMany/*(mappedBy = "element")*/
    @JoinColumn(name = "element_id")
    private List< Comment > comments;
//..

子实体

/**
 * Bean used to define a book or a document that contains one or many climbing areas
 */
@Entity
@Table(name="atlas")
@PrimaryKeyJoinColumn(name = "element_id")
@Getter
@Setter
@NoArgsConstructor
@ToString( exclude = {"areas" , "bookingRequests" , "user"})
public class Atlas extends Element {

//----------ATTRIBUTES----------

    @ManyToMany
    @JoinTable(
        name = "areas_in_atlases",
        joinColumns = { @JoinColumn(name = "atlas_id") },
        inverseJoinColumns = { @JoinColumn(name = "area_id") } )
    private List< Area > areas;
    private String scale;
    private String country;
    private String region;
    private String department;
    private boolean available;
    @ManyToOne
    @JoinColumn(name = "user_id")
    private User user;
    @OneToMany(mappedBy = "atlas", cascade = CascadeType.ALL)
    private List<BookingRequest> bookingRequests;
//..



/**
 * Bean used to define an area with one or many climbing crag
 */
@Entity
@Table(name="area")
@PrimaryKeyJoinColumn(name = "element_id")
@Getter
@Setter
@NoArgsConstructor
@ToString
@EqualsAndHashCode( callSuper = true )
public class Area extends Element {

//----------ATTRIBUTES----------

    @ManyToMany(mappedBy = "areas")
    private List< Atlas > atlases;
    private Atlas atlas;
    @OneToMany/*(mappedBy = "area", fetch = FetchType.LAZY)*/
    @JoinColumn(name = "area_id")
    private List< Crag > crags;
    private int approachDuration;
    private String locality;
    @OneToMany/*(mappedBy = "area", fetch = FetchType.LAZY)*/
    @JoinColumn(name = "area_id")
    private List< Parking > parking;
    private String rockType;
//..

我的多标准方法的第一部分正在工作(我猜不是很优雅......):

@Override
public Page<Atlas> searchAtlasByNameAndCountryAndRegionAndDepartment( int page, int size, String name, String country, String region, String department ){

    QAtlas qAtlas = QAtlas.atlas;

    ArrayList< Predicate > predicates = new ArrayList<>();

    List<Atlas> atlases;

    if( !name.equals( "" ) ){
        predicates.add( qAtlas.name.containsIgnoreCase(name) );
    }
    if( !country.equals( "" ) ){
        predicates.add( qAtlas.country.containsIgnoreCase(country) );
    }
    if( !region.equals( "" ) ){
        predicates.add( qAtlas.region.containsIgnoreCase(region) );
    }
    if( !department.equals( "" ) ){
        predicates.add( qAtlas.department.containsIgnoreCase(department) );
    }

    BooleanBuilder booleanBuilder = new BooleanBuilder();

    for ( Predicate predicate: predicates ) {
        booleanBuilder.and(predicate);
    }

    atlases = ( List< Atlas > ) getDaoFactory().getAtlasRepository().findAll( booleanBuilder );

    long total = ( long ) atlases.size( );

    return new PageImpl(atlases, PageRequest.of( page, size ), total );
}

但我坚持使用仅在 Atlas 中的字段(例如国家/地区)在区域中搜索的方法。

    @Override
    public Page< Area > searchAreaByNameAndCountryAndRegionAndDepartment( int page, int size, String name, String country, String region, String department ){

        QAtlas qAtlas = QAtlas.atlas;
        QArea qArea = QArea.area;

        final JPAQueryFactory queryFactory = new JPAQueryFactory(em);


        List<Area> areas = queryFactory.selectFrom(qArea)
                                   .innerJoin(qAtlas)
                                   .where(
                                           qArea.name.containsIgnoreCase(name),
                                           qAtlas.country.containsIgnoreCase(country),
                                           qAtlas.department.containsIgnoreCase(department),
                                           qAtlas.region.containsIgnoreCase(region)
                                   )
                                   .fetch();

        long total = ( long ) areas.size( );

        return new PageImpl(areas, PageRequest.of( page, size ), total );
    }

当前控制台显示:

ervlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.IllegalArgumentException: org.hibernate.hql.internal.ast.QuerySyntaxException: Invalid path: 'atlas.areas' [select area
from org.thibaut.wheretoclimb.model.entity.Area area
  inner join atlas.areas as area
where lower(area.name) like ?1 escape '!' and lower(atlas.country) like ?2 escape '!' and lower(atlas.department) like ?1 escape '!' and lower(atlas.region) like ?1 escape '!']] with root cause

org.hibernate.hql.internal.ast.QuerySyntaxException: Invalid path: 'atlas.areas' [select area
from org.thibaut.wheretoclimb.model.entity.Area area
  inner join atlas.areas as area
where lower(area.name) like ?1 escape '!' and lower(atlas.country) like ?2 escape '!' and lower(atlas.department) like ?1 escape '!' and lower(atlas.region) like ?1 escape '!']

有人可以帮我解决这个问题吗?

非常感谢你们抽出宝贵的时间!

最佳答案

解决方案:

public Page< Area > searchAreaByNameAndCountryAndRegionAndDepartment( int page, int size, String name, String country, String region, String department ){

        QAtlas qAtlas = QAtlas.atlas;
        QArea qArea = QArea.area;

        JPAQueryFactory queryFactory = new JPAQueryFactory(em);

        BooleanBuilder booleanBuilder = new BooleanBuilder();

        if( ! name.equals( "" ) ){
            booleanBuilder.and( qArea.name.containsIgnoreCase(name) );
        }
        if( ! country.equals( "" ) ){
            booleanBuilder.and( qAtlas.country.containsIgnoreCase(country) );
        }
        if( ! region.equals( "" ) ){
            booleanBuilder.and( qAtlas.region.containsIgnoreCase(region) );
        }
        if( ! department.equals( "" ) ){
            booleanBuilder.and( qAtlas.department.containsIgnoreCase(department) );
        }

        List<Area> areas = queryFactory.from(qAtlas)
                                   .innerJoin(qAtlas.areas, qArea)
                                   .where(booleanBuilder)
                                   .select(qArea)
                                   .fetch();

        long total = ( long ) areas.size( );

        return new PageImpl(areas, PageRequest.of( page, size ), total );
    }

非常感谢你们抽出宝贵的时间!

关于java - 如何在 JPAQuery 中使用 INNER JOIN?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53051635/

相关文章:

java - 将变量名称声明为方法参数的 Eclipse 快捷方式

java - ReSTLet 向服务器发送 "get"请求并处理响应

java - 关联该实体的最佳方式是什么

java - 无法在 Kotlin 中创建 Spring Data 事件监听器

spring - 扫描 PackagesToScan 时忽略一些类

javascript - 在Elasticsearch中搜索别名时如何引用各个索引中的特定字段?

java - 为什么 AutoClosaeble 使用 try/catch 语义?

java - DB2 插入性能

mysql - QueryDSL:比较数组

java - 如何使用QueryDslPredicateExecutor?