Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HHH-19096 Adjust SelectionQuery#setEntityGraph(..) to accept entity graphs of supertypes #9690

Conversation

marko-bekhta
Copy link
Member

https://hibernate.atlassian.net/browse/HHH-19096


By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license
and can be relicensed under the terms of the LGPL v2.1 license in the future at the maintainers' discretion.
For more information on licensing, please check here.


Copy link
Member

@mbladel mbladel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @marko-bekhta! Would be great if we could add a test for this though, just to ensure that 1. setEntityGraph accepts graphs of subtypes of the queried entity and 2. said graphs work as expected.

@gavinking
Copy link
Member

Are you sure this makes sense? Usually an EntityGraph for a supertype makes sense, not an EntityGraph for a subtype.

@marko-bekhta marko-bekhta force-pushed the fix/HHH-19096-Adjust-SelectionQuery-setEntityGraph-to-accept-entity-graphs-of-subtypes branch from c9c5b1c to 4929218 Compare February 3, 2025 18:35
Comment on lines 308 to 314
default SelectionQuery<R> setNamedEntityGraph(String graphName, GraphSemantic semantic) {
EntityGraph<? super R> namedEntityGraph = getNamedEntityGraph( graphName );
if ( namedEntityGraph == null ) {
throw new IllegalArgumentException( "No entity graph found for name " + graphName );
}
return setEntityGraph( namedEntityGraph, semantic );
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this felt like a more user-friendly way to apply that graph, but if you don't like it I'll drop it 😃

Copy link
Member

@gavinking gavinking Feb 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess I'm not very keen on it because it pushes people toward using string-based names whereas we're actively trying to discourage them from using strings.

What we really want them to do is use Entity_._NamedGraph to get a typesafe reference to the named entity graph from the static metamodel. We prefer that they don't use these string-based lookups.

So, while I'm fine with adding one new operation I'm not sure we want to bloat out the very important SelectionQuery interface with operations which only streamline the untypesafe usage.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤷🏻 😃 it's just when I was adding that test example:

SelectionQuery<Aa> query = s.createSelectionQuery( "from Aa", Aa.class );
query
    .setEntityGraph( 
        //  here:
        query.getNamedEntityGraph( "a-graph" ), GraphSemantic.FETCH )
    .getResultList();

above looks a bit odd to pass something to a query by getting it from the very same query.
IDK how often people generate the static metamodel in their projects, but if "this is the way" 😃 I'm ok with reverting this bit 😃 just let me know

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

above looks a bit odd to pass something to a query by getting it from the very same query.

Yes I understand that.

IDK how often people generate the static metamodel in their projects, but if "this is the way"

It's the new way in JPA 3.2. We want to encourage them to use it.

@Entity(name = "Aa")
static class Aa extends A {
@Id @GeneratedValue
Long id;

Check warning

Code scanning / CodeQL

Field masks field in super class Warning test

This field shadows another field called
id
in a superclass.
@marko-bekhta marko-bekhta force-pushed the fix/HHH-19096-Adjust-SelectionQuery-setEntityGraph-to-accept-entity-graphs-of-subtypes branch from 4929218 to 514df55 Compare February 4, 2025 07:39
@@ -273,7 +273,7 @@ default Stream<R> stream() {
* @param graph The graph to apply.
* @param semantic The semantic to use when applying the graph
*
* @deprecated Use {@link #setEntityGraph(EntityGraph, GraphSemantic)}
* @deprecated Use {@link SelectionQuery#setEntityGraph(EntityGraph, GraphSemantic)}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you make these changes?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😖🙈 hmm, I thought I've reverted all of these (IDE made the change when I updated the method signature through "refactoring" 🤦🏻 ) will revert these

@marko-bekhta marko-bekhta force-pushed the fix/HHH-19096-Adjust-SelectionQuery-setEntityGraph-to-accept-entity-graphs-of-subtypes branch from 514df55 to 2ed4355 Compare February 7, 2025 09:58
@marko-bekhta marko-bekhta changed the title HHH-19096 Adjust SelectionQuery#setEntityGraph(..) to accept entity graphs of subtypes HHH-19096 Adjust SelectionQuery#setEntityGraph(..) to accept entity graphs of supertypes Feb 7, 2025
@marko-bekhta marko-bekhta force-pushed the fix/HHH-19096-Adjust-SelectionQuery-setEntityGraph-to-accept-entity-graphs-of-subtypes branch from 2ed4355 to 5b9bd0f Compare March 14, 2025 20:25
@gavinking
Copy link
Member

@marko-bekhta a second option, which has some downsides, and which I'm not claiming is better, is to add the following method to QueryProducer:

	<R> Query<R> createQuery(String queryString, EntityGraph<R> resultClass);

This is a bit more consistent with EntityManager.find().

Here's what it looks like to use this method:

var query = session.createQuery( "from Client",
        session.getFactory().getNamedEntityGraphs( Client.class )
	        .get( "MyClientGraph" ) );
for ( Client client : query.getResultList() ) {
    String name = client.getName();
    ...
}

and according to an pre-existing proposal for JPA 4, this would simplify to:

var query = session.createQuery( "from Client",
        session.getNamedEntityGraphs( Client.class ).get( "MyClientGraph" ) );
for ( Client client : query.getResultList() ) {
    String name = client.getName();
    ...
}

which doesn't compare that unfavorably to what we have in this PR:

var query = session.createQuery( "from Client", Client.class );
query.setEntityGraph( query.getNamedEntityGraph( "MyClientGraph" ) );
for ( Client client : query.getResultList() ) {
    String name = client.getName();
    ...
}

@beikov
Copy link
Member

beikov commented Mar 27, 2025

How about we generate static fields for known entity graphs in the annotation processor and inject proxy implementations that disallow mutations? Then this could be as simple as this:

var query = session.createQuery( "from Client", Client_.MyClientGraph );

@marko-bekhta
Copy link
Member Author

TLDR: let's merge the ? super R part 😃


I went back to see what Search needed, as it's been a while 😃. Entity graphs affect internals, API ( but indirectly) and tests.

For internals, we might be building either a criteria or hql queries, and all we really need there is this change (? super R):

Query<R> setEntityGraph(EntityGraph<? super R> graph, GraphSemantic semantic);

For API, we let the user get an "ORM query" from the search one:

SearchQuery<IndexedEntity> searchQuery = ...
Query<IndexedEntity> query = Search.toOrmQuery( searchQuery );

so the users could then do

query.setEntityGraph( ... )

any way they wish 😃 (not a Search problem anymore).

Tests: for Search tests, we aren't building the static metamodel, and I wouldn't want to start doing that. I can live with

query.setEntityGraph(
    session.callSomethingEvenIfItDoesntLookGreatJustToGetTheGraphIWant( IndexedEntity.class, IndexedEntity.GRAPH_LAZY ),
    GraphSemantic.LOAD
);

With that said, the other changes beyond the ? super R were only to make it easier for users to get the graphs they want, hence not my call to make what's best 😃

@gavinking
Copy link
Member

How about we generate static fields for known entity graphs in the annotation processor and inject proxy implementations that disallow mutations?

We do already do that. It's a standard feature of JPA 3.2!

@marko-bekhta is worried about a different use case.

@gavinking
Copy link
Member

FTR, this is what I have currently proposed for JPA 4:

https://github.com/jakartaee/persistence/pull/705/files

@gavinking
Copy link
Member

On the other hand, thinking this through, there are some reasonably good arguments for adding an overload of createSelectionQuery(). (See Christian's code example.)

I went back to see what Search needed

@marko-bekhta When we're designing a public-facing API for ORM, we're not primarily thinking about what Search needs, OK?

@gavinking
Copy link
Member

gavinking commented Mar 28, 2025

On the other hand, thinking this through, there are some reasonably good arguments for adding an overload of createSelectionQuery().

Actually I think whatever we do with this proposal, we should add that overload anyway.

https://hibernate.atlassian.net/browse/HHH-19296

@marko-bekhta marko-bekhta force-pushed the fix/HHH-19096-Adjust-SelectionQuery-setEntityGraph-to-accept-entity-graphs-of-subtypes branch from 5b9bd0f to 56b507c Compare March 28, 2025 12:41
@marko-bekhta
Copy link
Member Author

I've updated this PR to only include the ? super R change.

@gavinking
Copy link
Member

LGTM

@gavinking
Copy link
Member

@marko-bekhta I would say you can just go ahead and merge this now

@marko-bekhta
Copy link
Member Author

ok, thanks! 🥳

@marko-bekhta marko-bekhta merged commit 000a041 into hibernate:main Mar 28, 2025
23 of 25 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants