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

Demonstrate solution for lazy-loading #33

Open
glassfishrobot opened this issue Oct 13, 2013 · 15 comments
Open

Demonstrate solution for lazy-loading #33

glassfishrobot opened this issue Oct 13, 2013 · 15 comments
Labels
backlog Items yet to be prioritized in the longer term roadmap. enhancement New feature or request Priority: Trivial

Comments

@glassfishrobot
Copy link

In the application some JPA relations are one-to-many and by default lazy loaded. When fetching the aggregate-root through the repository the returned root object will be detatched. Eclipselink handles this for read operations but Hibernate would throw a LazyInitializationException.

A traditional solution would be to add methods to a DAO such as loadCargoWithLoadedLegs();
With a lot of lazy collections and many combinations this would quickly be a bloated interface.

As a developer I would like to fetch the root, access and make changes to any object in graph, then store the root and have all changes persisted.

@glassfishrobot
Copy link
Author

@glassfishrobot Commented
Reported by danpeter

@glassfishrobot
Copy link
Author

@glassfishrobot Commented
Was assigned to reza_rahman

@glassfishrobot
Copy link
Author

@glassfishrobot Commented
reza_rahman said:
Would you still think it will be a bloated interface if it was something like: CargoRepository.find(TrackingId, LOADING_STRATEGY->[MINIMAL|DEFAULT|COMPLETE])? It's certainly not necessarily always the case, but what I have found in my experience is that lazy loading is actually surprisingly sparsely applied for many project (including this one). What other technique would you rather see that would fit DDD well? Would you mind doing a bit of research with the DDD community/other technologies and form a recommendation for us?

Keep in mind, we have a very important design alternatives section to the site planned where we can discuss various design alternatives and their pros/cons so that folks know about them and can make their own choices.

Also, we could make recommendations to the JPA EG that the EclipseLink behavior is more desirable and should be standardized .

Thanks for logging the issue and your interest in the project!

@glassfishrobot
Copy link
Author

@glassfishrobot Commented
danpeter said:
If the Project have very few lazy loaded Collections the least complex solution is preferred, in such a case a loading strategy is fine.

For more complex domain models the extended entity manager looks promising. I put this very simple sample together:
https://github.com/danpeter/extendedentitymanager

@glassfishrobot
Copy link
Author

@glassfishrobot Commented
reza_rahman said:
Sorry for the belated response to this - I just came back from a pretty hectic trip to India...

First a few comments on the code for your consideration:

  • JSF backing beans are not really controllers, but models - JSF and Wicket are the only two Java web frameworks that I know of to completely abstract away the controller responsibilities into the framework...
  • EntityManagers are actually not enrolled in stateful bean transactions unless they are explicitly referenced in the business method. In order to actually ensure a flush, I would add EntityManager.flush() to CompanyRepository.save(). I would also consider changing the repository API semantics to be more like CompanyRepository.save(Company). Besides CompanyRepository.save() being somewhat ambiguous (what is being saved - the repository or the entity?) imagine the unintended usage of invoking the getters multiple times. I think it's better to stick to the OO principle of abstraction and not force API users to understand implementation details.

Did you get a chance to check with the DDD community as to their thoughts on lazy loading? Last I checked, the consensus appeared to be that lazy loading was largely antithetical to DDD practices as indicated on this thread as an anecdote: http://stackoverflow.com/questions/15851122/domain-driven-design-entity-lazy-loading. That being said, I would not go so far as to categorizing lazy loading into an anti-pattern. Clearly there are cases where it is a valid technique. I just want to know what the current thinking is (I am sure this issue had to have been discussed).

Going the more classical DDD route, one option that might be of interest is JPA 2.1 entity graphs: http://www.datanucleus.org/products/datanucleus/jpa/entity_graphs.html.

Another interesting observation is that lazy loading actually is dealt with somewhat gracefully using DTOs at the application layer. It's only in the simplified layering case that I was trying to demonstrate that appears more complexity need be introduced in the repository layer...

Thoughts?

@glassfishrobot
Copy link
Author

@glassfishrobot Commented
danpeter said:
Hi, thanks for looking into the code. I think that Adam Bien describes it better than me here:
http://www.adam-bien.com/roller/abien/entry/building_perfect_anti_facades_almost he also mentions it as a good way to implement DDD in his book.

The nice thing with the extended persistance manager is that I can fetch the aggregate root object and traverse/modify the object graph in the the UI over several http request. Then when I am finished I call the save method on the reposity and all changes will be persisted/merged. Using the Word "flush" in the comment may have been a mistake.

Your stackoverflow link has a valid Point, maybe I am mixing DDD and data access too much.

I will have a look at entity graphs.

@glassfishrobot
Copy link
Author

@glassfishrobot Commented
reza_rahman said:
As much as I respect Adam, in this case, the empty save() method is unfortunately erroneous since it likely dependent upon implementation specific behavior (I am guessing in GlassFish). I would take a look at this and the JPA specification itself: http://stackoverflow.com/questions/7272354/why-do-we-have-to-manually-flush-the-entitymanager-in-a-extended-persistenceco.

I am also aware of Adam's views on DDD and unfortunately differ from them. In my long years of enterprise development, I can't begin to cite examples when layering and API abstraction has proven to be invaluable in keeping systems flexible, maintainable and technology agnostic in the long run.

That being said, we should document those views in this project as valid alternatives to choose, especially for relatively small, simple, young greenfield systems (sans the somewhat understandable misinterpretation/misunderstanding of the JPA automatic transaction enrollment/flush capability).

@glassfishrobot
Copy link
Author

@glassfishrobot Commented
This issue was imported from java.net JIRA CARGOTRACKER-33

@glassfishrobot
Copy link
Author

@glassfishrobot glassfishrobot self-assigned this Sep 16, 2019
@m-reza-rahman m-reza-rahman added enhancement New feature or request and removed ERR: Assignee Type: New Feature labels Sep 20, 2020
@thadumi thadumi added this to the jee8 milestone Oct 3, 2020
@m-reza-rahman m-reza-rahman removed this from the jakartaee8 milestone Nov 29, 2020
@m-reza-rahman m-reza-rahman added the backlog Items yet to be prioritized in the longer term roadmap. label Jan 4, 2021
@hantsy
Copy link
Contributor

hantsy commented Feb 25, 2021

This could be done by @EntityGraph. or a join fetch query.

@hantsy
Copy link
Contributor

hantsy commented Apr 7, 2021

Found a limitation when using @EntityGraph in WildFly/Hibernate,

The following definition does not work, https://stackoverflow.com/questions/17431312/what-is-the-difference-between-join-and-join-fetch-when-using-jpa-and-hibernate

@NamedEntityGraph(
    name = "Cargo.withItineraryLegs",
    attributeNodes = {@NamedAttributeNode(value = "itinerary", subgraph = "itinerary")},
    subgraphs = {
      @NamedSubgraph(
          name = "itinerary",
          attributeNodes = {@NamedAttributeNode("legs")})
    })

@hantsy
Copy link
Contributor

hantsy commented Apr 7, 2021

Use a join fetch in JPQL clause is working, see: aa99ee9#diff-b37a607550d90f061e56105444a10d95697c2e56e72b4ffe70e4af353ca143cfR51

@m-reza-rahman
Copy link
Contributor

Using join fetch is totally fine. It does not necessarily need to be entity graphs.

@hantsy
Copy link
Contributor

hantsy commented Apr 18, 2021

I think this can be closed when develop branch is merged.

@m-reza-rahman m-reza-rahman removed the backlog Items yet to be prioritized in the longer term roadmap. label Apr 18, 2021
@m-reza-rahman
Copy link
Contributor

There is some initial work on this done here: https://github.com/eclipse-ee4j/cargotracker/tree/wildfly-experimental.

@m-reza-rahman m-reza-rahman added good first issue Good for newcomers help wanted Extra attention is needed labels May 10, 2021
@m-reza-rahman m-reza-rahman added backlog Items yet to be prioritized in the longer term roadmap. and removed Priority: Minor labels Nov 2, 2021
@m-reza-rahman m-reza-rahman removed help wanted Extra attention is needed good first issue Good for newcomers labels Feb 7, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backlog Items yet to be prioritized in the longer term roadmap. enhancement New feature or request Priority: Trivial
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants