在 Criteria 中加入多个表会破坏预期的输出

问题描述 投票:0回答:1

我正在尝试在多个表中进行动态搜索。

当我加入ONLY一张表时,我得到了预期的输出。 当我连接所有表时,我只得到一半的结果,甚至没有。即使我不将 Predicates 包含在 criteriaBuilder.or(); 中,仅声明 JOINS 就会破坏代码。

实体:

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
   
   //Other fields...
  
    @ToString.Exclude
    @JsonIgnore
    @OneToMany(mappedBy = "imageInfo", fetch = FetchType.LAZY)
    private List<GenreImageInfoMEntity> genres;

    @ToString.Exclude
    @JsonIgnore
    @OneToMany(mappedBy = "imageInfo", fetch = FetchType.LAZY)
    private List<KeywordImageInfoMEntity> keywords;

    @ToString.Exclude
    @JsonIgnore
    @OneToMany(mappedBy = "imageInfo", fetch = FetchType.LAZY)
    private List<LocationImageInfoMEntity> locations;

    @ToString.Exclude
    @JsonIgnore
    @OneToMany(mappedBy = "imageInfo", fetch = FetchType.LAZY)
    private List<PersonImageInfoMEntity> persons;

加入实体:

@Getter
@Setter
@Entity
@Table(name = "genre_image_info_mapping",schema = "public")
public class GenreImageInfoMEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    Long id;

    @ManyToOne(cascade = CascadeType.DETACH)
    @JoinColumn(name = "fk_genre_id")
    GenreEntity genre;

    @ManyToOne(cascade = CascadeType.DETACH)
    @JoinColumn(name = "fk_image_info_id")
    ImageInfoEntity imageInfo;

}

加盟实体

@Entity
@Getter
@Setter
@Table(name = "genre",schema = "public")
public class GenreEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    Long id;

    @Column(name = "name")
    String name;
}

其他 3 个实体看起来相同。

规格

这种方式可以正常工作:

    private  Specification<ImageInfoEntity> fullSearch(String search) {
        return (root, query, criteriaBuilder) -> {

            Join<ImageInfoEntity, GenreImageInfoMEntity> joinG = root.join(ImageInfoEntity_.GENRES);
            String searchFinal = "%" + Utility.unaccent(search.toLowerCase()) + "%";

            Predicate genrePredicate = criteriaBuilder.like(criteriaBuilder.function("unaccent", String.class, criteriaBuilder.lower(joinG.get(GenreImageInfoMEntity_.GENRE).get(GenreEntity_.NAME))),searchFinal);
            return criteriaBuilder.or(genrePredicate);

        };
    }

这样我得到 0 个结果。

    private  Specification<ImageInfoEntity> fullSearch(String search) {
        return (root, query, criteriaBuilder) -> {

            Join<ImageInfoEntity, GenreImageInfoMEntity> joinG = root.join(ImageInfoEntity_.GENRES);
            Join<ImageInfoEntity, LocationImageInfoMEntity> joinL = root.join(ImageInfoEntity_.LOCATIONS);
            Join<ImageInfoEntity, PersonImageInfoMEntity> joinP = root.join(ImageInfoEntity_.PERSONS);
            Join<ImageInfoEntity, KeywordImageInfoMEntity> joinK = root.join(ImageInfoEntity_.KEYWORDS);

            String searchFinal = "%" + Utility.unaccent(search.toLowerCase()) + "%";

            Predicate genrePredicate = criteriaBuilder.like(criteriaBuilder.function("unaccent", String.class, criteriaBuilder.lower(joinG.get(GenreImageInfoMEntity_.GENRE).get(GenreEntity_.NAME))),searchFinal);
            Predicate personPredicate = criteriaBuilder.like(criteriaBuilder.function("unaccent", String.class, criteriaBuilder.lower(joinP.get(PersonImageInfoMEntity_.PERSON).get(PersonEntity_.SEARCH_NAME))),searchFinal);
            Predicate keywordPredicate = criteriaBuilder.like(criteriaBuilder.function("unaccent", String.class, criteriaBuilder.lower(joinK.get(KeywordImageInfoMEntity_.KEYWORD).get(KeywordEntity_.KEYWORD))),searchFinal);
            Predicate locationPredicate = criteriaBuilder.like(criteriaBuilder.function("unaccent", String.class, criteriaBuilder.lower(joinL.get(LocationImageInfoMEntity_.LOCATION).get(LocationEntity_.NAME))),searchFinal);
            Predicate locationHUNPredicate = criteriaBuilder.like(criteriaBuilder.function("unaccent", String.class, criteriaBuilder.lower(joinL.get(LocationImageInfoMEntity_.LOCATION).get(LocationEntity_.HUN_NAME))),searchFinal);
            Predicate locationENGPredicate = criteriaBuilder.like(criteriaBuilder.function("unaccent", String.class, criteriaBuilder.lower(joinL.get(LocationImageInfoMEntity_.LOCATION).get(LocationEntity_.ENG_NAME))),searchFinal);
            Predicate photographerPredicate = criteriaBuilder.like(criteriaBuilder.function("unaccent", String.class, criteriaBuilder.lower(root.get(ImageInfoEntity_.PHOTOGRAPHER).get(PersonEntity_.ABC_NAME))),searchFinal);
            Predicate ownerPredicate = criteriaBuilder.like(criteriaBuilder.function("unaccent", String.class, criteriaBuilder.lower(root.get(ImageInfoEntity_.OWNER))),searchFinal);
            return criteriaBuilder.or(genrePredicate,personPredicate,keywordPredicate,locationPredicate,locationENGPredicate,locationHUNPredicate,ownerPredicate,photographerPredicate);
            

        };
    }

其他规格:

    public Specification<ImageInfoEntity> build(FilterImageInfoDto filterImageInfoDto) {

        List<Specification<ImageInfoEntity>> specifications = new ArrayList<>();

        if(filterImageInfoDto.getSearch()!= null){
            specifications.add(fullSearch(filterImageInfoDto.getSearch()));
        }
        if(filterImageInfoDto.getSizeX()!= null){
            specifications.add(isSizeXEq(filterImageInfoDto.getSizeX()));
        }
        if(filterImageInfoDto.getSizeY()!= null){
            specifications.add(isSizeYEq(filterImageInfoDto.getSizeY()));
        }
        if(filterImageInfoDto.getCategory()!= null){
            specifications.add(isCategoryEq(filterImageInfoDto.getCategory().getId()));
        }
        if(filterImageInfoDto.getUploadDate()!= null){
            specifications.add(isUploadDateEq(filterImageInfoDto.getUploadDate()));
        }
        if(filterImageInfoDto.getCaptureYear()!= null){
            specifications.add(isCaptureYearEq(filterImageInfoDto.getCaptureYear()));
        }
        if(filterImageInfoDto.getTechnics()!= null  && !filterImageInfoDto.getTechnics().isEmpty() ){
            specifications.add(isTechnicsEq(filterImageInfoDto.getTechnics()));
        }
        if(filterImageInfoDto.getMaterials()!= null && !filterImageInfoDto.getMaterials().isEmpty()){
            specifications.add(isMaterialsEq(filterImageInfoDto.getMaterials()));
        }
        if(filterImageInfoDto.getGenres()!= null&& !filterImageInfoDto.getGenres().isEmpty()) {
            specifications.add(isGenreEq(filterImageInfoDto.getGenres()));
        }
        if(filterImageInfoDto.getPersons()!= null && !filterImageInfoDto.getPersons().isEmpty()){
            specifications.add(isPersonEq(filterImageInfoDto.getPersons()));
        }
        if(filterImageInfoDto.getPhotographers()!= null && !filterImageInfoDto.getPhotographers().isEmpty()){
            specifications.add(isPhotographerEq(filterImageInfoDto.getPhotographers()));
        }
        if(filterImageInfoDto.getLocations()!= null && !filterImageInfoDto.getLocations().isEmpty()){
            specifications.add(isLocationEq(filterImageInfoDto.getLocations()));
        }
        if(filterImageInfoDto.getKeywords()!= null && !filterImageInfoDto.getKeywords().isEmpty()){
            specifications.add(isKeywordLike(filterImageInfoDto.getKeywords()));
        }
        if(filterImageInfoDto.getHolders()!= null && !filterImageInfoDto.getHolders().isEmpty()){
            specifications.add(isHolderEq(filterImageInfoDto.getHolders()));
        }

        return  specifications.stream()
                .reduce(Specification::and)
                .orElse(null);
    }

我错过了什么?

我尝试将其分解为不同的函数,但没有任何帮助。

java postgresql spring-boot criteria specifications
1个回答
0
投票

解决方案:

Predicate personPredicate = 
criteriaBuilder.like(criteriaBuilder.function("unaccent", String.class, criteriaBuilder.lower(**joinP.get(PersonImageInfoMEntity_.PERSON).get(PersonEntity_.SEARCH_NAME)**)),searchFinal);

在上面的代码片段中:

joinP.get(PersonImageInfoMEntity_.PERSON).get(PersonEntity_.SEARCH_NAME)

进行加入。但这些类型的 JOIN 都是普通的 JOIN,这限制了输出。

所以基本上,通过在每次获取时手动连接,您可以指定连接类型。

    Join<GenreImageInfoMEntity, GenreEntity> joinGGenre = joinG.join(GenreImageInfoMEntity_.GENRE, JoinType.LEFT);
 Predicate genrePredicate = criteriaBuilder.like(criteriaBuilder.function("unaccent", String.class,
    criteriaBuilder.lower(joinGGenre.get(GenreEntity_.NAME))),searchFinal);
© www.soinside.com 2019 - 2024. All rights reserved.