"select new" + "join fetch" = "owner of the fetched association was not present in the select list"

Description

I want to create a List<B>, each B containing an entity with "A" type, and I also want for each A to force fetching of its "C" property.

public class B {
private A a;
public B(A a) {
this.a = a;
}
}

@Entity
public class A {
@ManyToOne @JoinColumn
private C c;
// +get/setter ...
}

@Entity
public class C {
@Column
private String d;
// +get/setter ...
// +@OneToMany
}

Here is the HQL :
select new B(a) from A a left join fetch a.c

I have that message :
org.hibernate.QueryException: query specified join fetching, but the owner of the fetched association was not present in the select list

When invoking only "from A a left join fetch a.c", all is good and I have ma List<A> with its "C" properties fetched.

I think there is a little bug here ... or did I forget something ?

Environment

None

Activity

Show:
Christian Beikov
November 18, 2015, 9:04 AM

How come you think that is invalid? Here the excerpt from JPQL BNF

constructor_expression ::=
NEW constructor_name ( constructor_item {, constructor_item}* )
constructor_item ::=
single_valued_path_expression |
scalar_expression |
aggregate_expression |
identification_variable

As you can see, identification_variable is perfectly fine there.

Christian Beikov
November 18, 2015, 9:07 AM

Also for reference see JPA spec 4.8.2 where it explicitly says, that such entities which are passed into the constructor must be in managed state.

PieterV
November 19, 2015, 7:25 AM

@steve please review the comment of @christian.beikov

Steve Ebersole
September 29, 2016, 5:54 PM

I spoke with about this on HipChat.

Sure, you can use an identification_variable as an argument. E.g. select new DTO( a ) from Animal a. That's really all JPA says on the matter. And in fact Hibernate supports that. That is a perfectly valid query that Hibernate will gladly parse and execute for you.

What you are asking for as a specific interpretation of what that means, which I am sorry but JPA does not say specifically. It does not say that the constructor should take the thing referenced by the identification_variable versus the id of the thing referenced by the identification_variable versus anything else. The closest it comes is in section 4.8.2 Constructor Expressions in the SELECT Clause, where it says:

If a single_valued_path_expression or identification_variable that is an argument to the constructor references an entity, the resulting entity instance referenced by that single_valued_path_expression or identification_variable will be in the managed state.

I can certainly see the argument that this should imply that the constructor should accept the entity here. However, as far as specs go, implying something and requiring it are 2 VASTLY different things.

The interpretation where we expect the constructor to accept the entity rather than the id goes against some basic and deep assumptions of Hibernate query parsing internals which pre-date JPA. I do not plan on changing this against those internals short of the JPA spec getting a revision that explicitly mandates expectations on the ctor args.

Now with 6.0 we are re-writing query parsing and execution from scratch. I will reconsider this wrt the work for 6.0 which is based on a new "semantic interpretation" model (SQM). SQM defines much different (better) support for "dynamic instantiation". For example, you can now define multiple constructor expressions in a query, you can nest constructor expressions, etc. How the SQM is interpreted into SQL is still ongoing. The SQM has the information needed to make this alternate decision. Like I said, I am open to reconsidering this for 6.x. But this will certainly not change for any releases prior to 6

Steve Ebersole
September 29, 2016, 5:56 PM

specifically I say it is invalid because of the interpretation Hibernate makes - the owner of that fetch is NOT part of the select list.

Assignee

Unassigned

Reporter

Anthony Ogier

Fix versions

None

Labels

backPortable

None

Suitable for new contributors

None

Requires Release Note

None

Pull Request

None

backportDecision

None

Affects versions

Priority

Major
Configure