1

Entity:

public class PlayerDetails implements Serializable{
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    @JoinColumn(name = "batting_stat_id", referencedColumnName = "id")
    private BattingStats battingStats;

    @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    @JoinColumn(name = "bowling_stat_id", referencedColumnName = "id")
    private BowlingStats bowlingStats;
    }

Repository code:

 String queryString = "select p from PlayerDetails p inner join fetch p.battingStats b where p.name = :name";
TypedQuery<PlayerDetails> query = entityManager.createQuery(queryString, PlayerDetails.class);
query.setParameter("name", name);

PlayerDetails playerDetails = query.getSingleResult();

String queryString2 = "select p from PlayerDetails p inner join fetch p.bowlingStats b where p.name = :name";
TypedQuery<PlayerDetails>  query2 = entityManager.createQuery(queryString2, PlayerDetails.class);
query2.setParameter("name", name);
PlayerDetails resultList2 = query2.getSingleResult();

playerDetails.setBowlingStats(resultList2.getBowlingStats());

return Optional.ofNullable(playerDetails);

I am fetching the BattingsStats and Bowling Stats using the JOIN FETCH, the queries are being fired correctly, the first time fetches the PlayerDetails fields along with BattingStats fields.

The second query fetches the PlayerDetails and BowlingStats fields. But when I inspect each fetched object, the BowlingStat is lazy loaded and returning a proxy. While serialization, I am getting:

            com.fasterxml.jackson.databind.exc.InvalidDefinitionException: 
        No serializer found for class org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor 
    and no properties discovered to create BeanSerializer (to avoid exception, disable
     SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: 
    com.example.model.response.ResponseModel["playerDetails"]-
com.example.entity.PlayerDetails["bowlingStats"]-
com.example.entity.BowlingStats$HibernateProxy$5RK3X4j1["hibernateLazyInitializer"])

Queries being fired:

select playerdeta0_.id as id1_2_0_, 
    battingsta1_.id as id1_0_1_, 
    playerdeta0_.batting_stat_id as batting_7_2_0_, 
    playerdeta0_.bowling_stat_id as bowling_8_2_0_, 
    playerdeta0_.name as name2_2_0_, 
    playerdeta0_.nationality as national3_2_0_, 
    playerdeta0_.role as role4_2_0_, 
    playerdeta0_.team as team5_2_0_, 
    playerdeta0_.value as value6_2_0_, 
    battingsta1_.batting_average as batting_2_0_1_, 
    battingsta1_.centuries as centurie3_0_1_, 
    battingsta1_.fours as fours4_0_1_, 
    battingsta1_.half_centuries as half_cen5_0_1_, 
    battingsta1_.highest_score as highest_6_0_1_, 
    battingsta1_.innings as innings7_0_1_, 
    battingsta1_.matches as matches8_0_1_, 
    battingsta1_.sixes as sixes9_0_1_, 
    battingsta1_.strike_rate as strike_10_0_1_ 
from player_details playerdeta0_ 
inner join batting_stats battingsta1_ 
    on playerdeta0_.batting_stat_id=battingsta1_.id 
where playerdeta0_.name=?


select playerdeta0_.id as id1_2_0_, 
        bowlingsta1_.id as id1_1_1_, 
        playerdeta0_.batting_stat_id as batting_7_2_0_, 
        playerdeta0_.bowling_stat_id as bowling_8_2_0_, 
        playerdeta0_.name as name2_2_0_, 
        playerdeta0_.nationality as national3_2_0_, 
        playerdeta0_.role as role4_2_0_, 
        playerdeta0_.team as team5_2_0_, 
        playerdeta0_.value as value6_2_0_, 
        bowlingsta1_.balls_bowled as balls_bo2_1_1_, 
        bowlingsta1_.economy as economy3_1_1_, 
        bowlingsta1_.five_wicket_haul as five_wic4_1_1_, 
        bowlingsta1_.wickets as wickets5_1_1_ 
    from player_details playerdeta0_ 
    inner join bowling_stats bowlingsta1_ 
        on playerdeta0_.bowling_stat_id=bowlingsta1_.id 
    where playerdeta0_.name=?

Fetched Data from the first query

Fetched Data from the second query

Can someone help me with this?

PS: The error is not by hibernate, the error is when Jackson tries to parse the data; for now, I am just returning the entity directly.

My question is not how to remove this error? My question is why this behaviour by hibernate? Though I am fetching the same record multiple times in the same session (which as told by Alex is a bad pattern and I changed it, but thanks to bad smelly code, I can learn something here !!!) I am fetching the same record with two different queries in the same session and though two different queries are fired to fetch the associations, why the second association is always treated as proxy (as if lazy loaded)- I say second fetched association since as mentioned by @Alex, I swapped the queries and the same problem now association fetched second. despite of two different queries firing (which are correct) I getting this. I think this has something to do with the session is managing the persistent entity. Please do let me know or any article , cause I am starting to think, my understanding is wrong here.

Thanks.

5
  • Have you tried enabling Jackson's Hibernate5Module? Commented Mar 21, 2020 at 13:57
  • No, I removed the issue with a single query. My question is rather why such behavior . Commented Mar 21, 2020 at 15:08
  • 1
    If you fetch the same entity using queries twice while in the context of the same persistence unit, the second time around you'll get the exact same instance of that entity (note that the object ids of PlayerDetails are the same in both cases). Therefore, the JOIN FETCH in the second query cannot possibly have any effect Commented Mar 21, 2020 at 17:06
  • 1
    It's also pretty obvious why JPA was designed to never allow two instances of the same entity into a single persistence context: if you call playerDetails.setName("John") and resultList2.setName("Gary"), which version 'wins' at persist time? Commented Mar 21, 2020 at 17:08
  • Thanks. Your explanation makes sense now. My understanding was really sad. Thanks for helping out. If you can post this comment as an answer, cause I wanna upvote your answer. Commented Mar 21, 2020 at 18:32

2 Answers 2

3

If you fetch the same entity using queries twice while in the context of the same persistence unit, the second time around you'll get the exact same instance of that entity (note that the object ids of PlayerDetails are the same in both cases). Therefore, the JOIN FETCH in the second query cannot possibly have any effect.

It's also pretty obvious why JPA was designed to never allow two instances of the same entity into a single persistence context: if you call playerDetails.setName("John") and resultList2.setName("Gary"), which version 'wins' at persist time?

Sign up to request clarification or add additional context in comments.

Comments

2

Why do you need two queries? Entity fields have to be managed by entity manager. You can set fields only for saving to database. Otherwise, you should use dto projection instead of entity as query result.

Try this

String queryString = "select p from PlayerDetails p join fetch p.battingStats bts join fetch p.bowlingStats bws where p.name = :name";
TypedQuery<PlayerDetails> query = entityManager.createQuery(queryString, PlayerDetails.class);
query.setParameter("name", name);

return Optional.ofNullable(query.getSingleResult());

11 Comments

I was using this query to fetch the associations, but I changed the query cause I will be changing the associations to List (One to Many ) to support a feature.
But strangely, doesnt make sense that join fetch battingStats loads the battingStat association and not the bowlingStats association and the query trgiggerd is also fine. When done with bowlingStats, though the query fired is fine, still batting is being eagely loaded and the bowling stats is a proxy !!!!! I still don't get why is this happening ?
The problem is that you set bowlingStats from one entity to another. If you swap queries and set battingStats you get the same problem for battingStats field
Sorry, I still dont understand. A has association to B and C. A inner join fetch B -> eagerly loads B with inner join. This is the first query. In a separate query, A joint fetch C loads C eagerly . But here, despite firing two queries and I can see the query doing correct joins, the second query os fetching C lazily and B eagerly .
It is wrong approach to make entity manager manage two different version of the same record
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.