Hibernate Specification for Join

Viewed 27

I try to select the Article list by Tag which join by foreign key:

@Repository
public interface ArticleRepository extends JpaRepository<Article, Long>, JpaSpecificationExecutor<Article> {}

// Service call
public List<Article> findAllArticlesWithTag(String tag) {
    return articleRepository
            .findAll(articleSpecificationFactory.allArticlesWithTag(tag));
}

The problem in Specification factory method allArticlesWithTag(String tag)

public Specification<Article> allArticlesWithTag(String tag) {
        return new Specification<Article>() {
            @Override
            public Predicate toPredicate(Root<Article> root,
                                         CriteriaQuery<?> query,
                                         CriteriaBuilder builder) {
                Predicate predicate = builder.conjunction();
                if (Objects.nonNull(tag) && !tag.isBlank()) {
                    predicate.getExpressions().add(
                                 builder.in(builder.equal(root.get("tags"), tag))); // problem here
                }
                return predicate;
            }
        };
    }

How can I implement toPredicate for correct selection articles by tag?

SQL scheme:

CREATE TABLE IF NOT EXISTS articles
(
    id      BIGSERIAL PRIMARY KEY,
    title   VARCHAR(255) UNIQUE
);

CREATE TABLE IF NOT EXISTS tags
(
    article_id BIGINT REFERENCES articles (id),
    tag        VARCHAR(255)
);

But Tag entity no has its own java entity and represent as @ElementCollection:

@Getter
@Setter
@Entity
@ToString
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "articles")
public class Article {

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

    @ElementCollection(targetClass = String.class,
            fetch = FetchType.EAGER)
    @CollectionTable(name = "tags",
            joinColumns = @JoinColumn(name = "article_id"))
    @Column(name = "tag")
    private List<String> tags = new ArrayList<>();
}

I think it's should be a combination of CriteriaBuilder builder calls but how exactly? builder.in(builder.equal(root.get("tags"), tag)) is wrong.

0 Answers
Related