matgr
matgr

Reputation: 117

Mapping many-to-many IN statement into JPA (Spring Boot)

I have created two entities in JPA, Listing and ItemType - these exist in a many-to-many relationship (Hibernate auto-generates a junction table). I'm trying to find the best way to create a query which accepts a dynamic list of item type Strings and returns the IDs of all listings which match the specified item types, but I am a recent initiate in JPA.

At present I'm using JpaRepository to create relatively simple queries. I've been trying to do this using CriteriaQuery but some close-but-not-quite answers I've read elsewhere seem to suggest that because this is in Spring, this may not be the best approach and that I should be handling this using the JpaRepository implementation itself. Does that seem reasonable?

I have a query which doesn't feel a million miles away (based on Baeldung's example and my reading on WikiBooks) but for starters I'm getting a Raw Type warning on the Join, not to mention that I'm unsure if this will run and I'm sure there's a better way of going about this.

public List<ListingDTO> getListingsByItemType(List<String> itemTypes) {

    List<ListingDTO> listings = new ArrayList<>();

    CriteriaQuery<Listing> criteriaQuery = criteriaBuilder.createQuery(Listing.class);

    Root<Listing> listing = criteriaQuery.from(Listing.class);
    //Here Be Warnings. This should be Join<?,?> but what goes in the diamond?
    Join itemtype = listing.join("itemtype", JoinType.LEFT);

    In<String> inClause = criteriaBuilder.in(itemtype.get("name"));

    for (String itemType : itemTypes) {

        inClause.value(itemType);

    }

    criteriaQuery.select(listing).where(inClause);

    TypedQuery<Listing> query = entityManager.createQuery(criteriaQuery);

    List<Listing> results = query.getResultList();

    for (Listing result : results) {

        listings.add(convertListingToDto(result));

    }

    return listings;

}

I'm trying to understand how best to pass in a dynamic list of names (the field in ItemType) and return a list of unique ids (the PK in Listing) where there is a row which matches in the junction table. Please let me know if I can provide any further information or assistance - I've gotten the sense that JPA and its handling of dynamic queries like this is part of its bread and butter!

Upvotes: 0

Views: 114

Answers (1)

JB Nizet
JB Nizet

Reputation: 691755

The criteria API is useful when you need to dynamically create a query based on various... criteria.

All you need here is a static JPQL query:

select distinct listing from Listing listing 
join listing.itemTypes itemType 
where itemType.name in :itemTypes

Since you're using Spring-data-jpa, you just need to define a method and annotate it with @Query in your repository interface:

@Query("<the above query>")
List<Listing> findByItemTypes(List<String> itemTypes)

Upvotes: 2

Related Questions