Section 28.6 of the hibernate manual mentions that you shouldn't use entity queries for read only fetching, as they suffer from requesting too much data.
This makes sense, we've seen that complicated domain models can lead to very long running queries, especially when working with table views.
The manual goes on to note:
For read-only transactions, you should fetch DTO projections because they allow you to select just as many columns as you need to fulfill a certain business use case.
But AFAIK JPA doesn't provide a good way for fetching these projections, you are left playing with the criteria builder, which we've found is verbose, brittle and every so often fails to work properly (implementation is hard).
Indeed looking at various posts on SO shows that lots of people are using entities for reads. So the questions I pose are as follows:
- Is avoiding read-only entity queries common in real world enterprise applications, I get the feeling it isn't.
- If it is, what tools are people using to make this bearable, a seperate query dsl comes to mind, jOOQ?
- Are there any resources where best practices are laid out for the architecture of a Spring app with a connection to a persistence layer (I'm thinking of other complicated issues that could cause problems, such as transaction management), it seems everyone seems to take an ad-hoc approach.
CodePudding user response:
You have to understand that there is no definitive answer and everyone will give you different suggestions/advice based on their experience.
Generally, the preferred solution is to use a DTO approach, but how you implement that is left as an exercise for the developer. Some developers are too lazy or simply accept/cope with the possible negative effects of using entity queries. It really depends on your use case and your needs.
I think though, that what you are looking for is a solution like Blaze-Persistence Entity Views.
I created the library to allow easy mapping between JPA models and custom interface or abstract class defined models, something like Spring Data Projections on steroids. The idea is that you define your target structure(domain model) the way you like and map attributes(getters) via JPQL expressions to the entity model.
A DTO model for an example use case could look like the following with Blaze-Persistence Entity-Views:
@EntityView(User.class)
public interface UserDto {
@IdMapping
Long getId();
String getName();
Set<RoleDto> getRoles();
@EntityView(Role.class)
interface RoleDto {
@IdMapping
Long getId();
String getName();
}
}
Querying is a matter of applying the entity view to a query, the simplest being just a query by id.
UserDto a = entityViewManager.find(entityManager, UserDto.class, id);
The Spring Data integration allows you to use it almost like Spring Data Projections: https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features
Page<UserDto> findAll(Pageable pageable);
The best part is, it will only fetch the state that is actually necessary!
CodePudding user response:
I've seen many people doing LAZY fetching for associations, that avoids big joins if you don't need data from other tables, and usually solves the problem. However, the fetch strategy cannot be overridden per query, so you cannot choose to do LAZY fetching for some queries and then do EAGER fetching for others.
DTO projections are indeed a better alternative. In pure JPA that requires messing with CriteriaBuilder.construct(....)
, but Spring JPA has a very nice wrapper for it: https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#projections
With DTO projections only the columns and joins you need will be included in the query.
For very large read-only operations, like reporting usecases, it's better to not use ORM frameworks, but use some specialized data frameworks.