I am using Spring Boot with Spring Data and attempting to write unit tests.
I have a three tables: Orders have more than one Taco. Tacos have more then one ingredient.
I am attempting to read an Order, with all its Tacos, and the Ingredients for each Taco.
In Order, tacos is a list. In Taco, ingredients is a list.
Here are some good references:
JPQL queries. https://www.objectdb.com/java/jpa/query/jpql/from
EntityGraphs: https://www.radcortez.com/jpa-entity-graphs/
Problems with EntityGraphs: https://stackoverflow.com/questions/31943989/spring-data-jpa-and-namedentitygraphs
JPA LifeCycle: https://www.javabullets.com/jpa-entity-lifecycle/
Baeldung EntityGraph example: https://www.baeldung.com/jpa-entity-graph
Removing old data from cache when testing: https://stackoverflow.com/questions/19057802/junit-hibernate-testing-lazy-associations-fetched
Transactional testing: https://www.marcobehler.com/2014/06/25/should-my-tests-be-transactional
I have tried many ways to complete the task. The most fruitful was with EntityGraph.
When I attempted the query, I received a Hibernate multiple bag exception.
I researched many articles on the net. One solution is to use a set, but one site cautioned against that, since it must create a Cartesian product of all the tables.
https://vladmihalcea.com/hibernate-multiplebagfetchexception/
I tried to follow the advice, but my example is a little different. I believe the example uses the same approach as nested select statements. I cannot use that idea, since that example is accessing two collections from the same parent table. I want to get all tacos for an order, then get all ingredients for each of those tacos. I cannot perform a join on tacos.ingredients, since tacos is a list. I would have to join on the elements in the list.
I am beginning to think that the best solution is to change to sets instead of lists. Without it, I am forced to do a separate select to get the ingredients for each taco and then add those ingredients to the original result set of the tacos in the order.
Here is a new thought: read all the tacos with their ingredients. Somehow, organize these tacos into orders. Bad idea.
I imagine there is no other way than creating the Cartesian product. I will try with sets.
I attempted to work with sets. The changes were minimal, since many of the methods return Iterable.
I used an EntityGraph with a subgraph for ingredients, but it failed with a null pointer exception.
@NamedEntityGraph(
name = "Taco_Order.detail",
attributeNodes = {
@NamedAttributeNode(value="tacos"
,subgraph="tacos-subgraph"
)
}
,subgraphs = {
@NamedSubgraph(
name="tacos-subgraph",
attributeNodes= {
@NamedAttributeNode("ingredients")
})
}
)
If I removed the subgraph, it worked, it even retrieved the ingredients. Confusing.
I removed the entity graph and debugged the code. The tacos were not loaded, as was expected.
I will add the entity graph again and see what happens. It may be a case of stale data in the session. I still got the ingredients. I had added an eager findById to taco, maybe that caused a problem.
I am stuck. I do not know why the ingredients are read.
250 - New
9 years ago
No comments:
Post a Comment