8

We have a Media object:

public class Media implements Serializable {

    @Id
    @GeneratedValue(strategy = IDENTITY)
    @Column(insertable = false, updatable = false)
    private Long id;
    // other attributes
    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "channelId", referencedColumnName = "id")
    private Channel channel;
    // getters, setters, hashCode, equals, etc.

}

The eager fetch of the channel parent works in regular repository methods, but not when using a Specification.

Here's the Specification:

public class MediaSpecs {

public static Specification<Media> search(final Long partnerId, final Integer width, final Integer height,
        final String channelType) {

    return new Specification<Media>() {

        @Override
        public Predicate toPredicate(Root<Media> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
            Predicate restrictions = cb.equal(root.get("archived"), false);
            // other restrictions are and-ed together
            if (channelType != null) {
                    Join<Media, ChannelType> join = root.join("channel").join("orgChannelType").join("type");
                restrictions = cb.and(cb.equal(join.get("type"), channelType));
            }
            return restrictions;
        }
    };
}

The "search" spec works correctly when channelType is specified, so the join is working. How do I specify that the joins should be eagerly fetched?

I tried adding

Fetch<Media, ChannelType> fetch = root.fetch("channel").fetch("orgChannelType").fetch("type");

Then Hibernate throws an exception:

org.hibernate.QueryException: query specified join fetching, but the owner of the fetched association was not present in the select list [FromElement{explicit,not a collection join,fetch join,fetch non-lazy properties,classAlias=generatedAlias4 ...

How do I add the associations to the select list?

Thanks.

Eric
  • 283
  • 5
  • 12

2 Answers2

16

I think you have problem with count query. Usually the specification is use for data query a and count query. And for count query there is no "Media". I use this workaround :

Class<?> clazz = query.getResultType();
if (clazz.equals(Media.class)) {
    root.fetch("channel");
}

This use fetch only for data query a not for count query.

Tomas Jacko
  • 345
  • 3
  • 11
  • Great! Thanks a lot. By the way, I had wondered why two logs being printed in console if I added logging one line. This is the reason as well. – HanByul Lee Aug 10 '18 at 02:17
4

For example:

public Predicate toPredicate(Root<Person> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                if (Long.class != query.getResultType()) {
                    root.fetch(Person_.addresses);
                }
                return cb.conjunction();
            }
Eugene
  • 71
  • 1