I'm trying to exclude byte field from my object query since there are several hundreds or thousand of reports and it takes a long time to query it from the database.
public class Reports
{
private int id;
private String reportName;
#Lob
#Basic(fetch= FetchType.LAZY)
private byte[] file;
private Date createdDate;
}
I tried setting up the hibernate byte enhancement for this How to setup Hibernate Gradle plugin for bytecode enhancement? but I'm still getting the file when I query all the reports. Did I missed something here?
In JPA, you can annotate a field with #Transient to indicate that it is not persistent.
Bytecode enhancement should help, but maybe you didn't configure it correctly or the Hibernate version you are using has a bug. I'd need to know details or see a reproducing test case to help you with that.
You could try to use java.sql.Blob instead which is guaranteed to be lazy and doesn't require byte code enhancement.
Apart from that, I would recommend you use DTO projections for actually fetching just the data that you need. I think this is a perfect use case for 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 your use case could look like the following with Blaze-Persistence Entity-Views:
#EntityView(Reports.class)
public interface ReportsDto {
#IdMapping
int getId();
String getReportName();
Date getCreatedDate();
Set<ReportRowDto> getRows();
#EntityView(ReportRows.class)
interface ReportRowDto {
#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.
ReportsDto a = entityViewManager.find(entityManager, ReportsDto.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
The DTO projection is validated against the entity model and it will only fetch what is necessary. Spring Data Projections falls back to "just" wrapping entities when the projection is too complex, whereas Blaze-Persistence Entity-Views will alter the query as if you had written it by hand :)
Related
I am trying to avoid in-memory pagination and N+1 while using Spring Data JPA Specification.
To be specific, I'm using the below method provided by the framework.
Page<T> findAll(#Nullable Specification<T> spec, Pageable pageable);
I tried to avoid N+1 by using #EntityGraph on the method (don't know if it's good or not) and after some research, I still don't know how to work around the in-memory pagination.
The database I'm using is Postgres if it matters
Are there any solutions to this problem?
The problem is that as soon as you fetch some kind of *-to-many association, Hibernate will do in-memory pagination, so #EntityGraph won't help. What you need is a special query that does pagination on the main/root entity and fetches associations in a second query.
I think this is a perfect use case for 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 your 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(Specification spec, Pageable pageable);
The best part is, it will only fetch the state that is actually necessary!
But you can even use it with plain entities if you like in which case this will also run more efficient queries as you can read about in the documentation: https://persistence.blazebit.com/documentation/core/manual/en_US/index.html#pagination
Is it possible to load #*ToOne attributes eagerly using JPA interface(Entity Graphs) which are set lazy using #LazyToOne , #LazyGroup in the parent entity class and enabled bytecode enhancement ? I am trying to load such attributes eagerly using entity graph but it is firing another query for such #*ToOne attributes when an parent entity is queried.
Trying to have another way to override static fetch type in entity classes including #LazyToOne which was added with bytecode enhancement.
Using Spring 5.1.3 , Spring JPA 2.2 , Hibernate 5.4.19
Update : Data JPA is working as expected and i could see joins for the attributes which i am trying to fetch eagerly but those lazy attributes are not being initialised with the join query response and hibernate causing each query on referencing attributes which were annotated with #LazyToOneOption.NO_PROXY and was already fetched eagerly using entity graph in my repository.
How can i avoid this second select which is not even required since i got the that data eagerly from entity graph in JPA respository ??
Any help would be highly appreciated.
Entity Graphs just like Hibernate fetch profiles apply regardless of what annotations you have on the association. If it does not, maybe there is a bug in Spring Data or maybe even Hibernate. It's probably best if you create a new JIRA issue with a test case reproducing the problem.
Having said that, I think this is the perfect use case for 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.
An example DTO model 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();
}
// Other mappings
}
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
As I am new to Spring boot. I am not at all clear about mappings. By using #Onetomany mapping in one entity and #manytoOne mapping at other entities. Using the controller I have to write REST API functions to insert multiple users at a time inside an array or set. Can anyone please suggest some websites or provide some existing codes?
The #OneToMany and #ManyToOne mappings can be used according to your use-case, whether you need bi-directional mappping or not. For a simple example consider the following :
#Entity
#Table(name="ENTITY_A")
public class EntityA{
//...
#OneToMany(mappedBy="EntityA")
private Set<EntityB> entityBItems;
// getters and setters
}
#Entity
#Table(name="ENTITY_B")
public class EntityB{
//...
#ManyToOne
#JoinColumn(name="entityA_id", nullable=false)
private EntityA entityA;
public EntityB() {}
// getters and setters
}
What you need to look out for is the owning side of the relation indicated by the mappedBy . The owning entity can be used to persist and get the data from the database. But from the description in your question I cannot understand whether you actually need to use mappings at all as you just have to insert multiple users into a table without any relations to another entity. It will be more helpful if you could explain more about your use case and provide code samples for furthur analysis.
For details about the mappings article or article .
Official doc .
MappedBy signals hibernate that the owner of key (relationship) is on the other side.
This means that although you link 2 tables together, only 1 of those tables has a foreign key constraint to the other one.
MappedBy allows you to still link from the table not containing the constraint to the other table.
If you still want use #JoinColumn on both the Entities you can use #JsonManagedReference and #JsonBackReference from com.fasterxml.jackson
To save the multiple records at same time you can use yourRepository.saveAll(entities)
If i have several entites, lets say :
#Entity
class Book{
String name;
Author author;
}
#Entity
class Author{
String name;
City hometown;
}
#Entity
class City{
String cityName;
}
If i want to retrieve all the books, if i use classic JPA Repository and Spring Data and just do a findAll(), it will get me all the books with all the Authors with all their home towns. I know i can use #JsonIgnore, but i think that only prevents whats being returned, not whats being looked up in the database. And also i have methods that DO want to return both books and authors, so #JsonIgnore -ing does not work for me. Is there anything like this ? To tell Spring Data what to look up and what to return ? Any links or guides or methods i don't know of, would be appreciated.
Spring Data has the concept of 'projections' which allow you to return different representations of the same Entity.
Official Documentation:
Spring Data query methods usually return one or multiple instances of
the aggregate root managed by the repository. However, it might
sometimes be desirable to create projections based on certain
attributes of those types. Spring Data allows modeling dedicated
return types, to more selectively retrieve partial views of the
managed aggregates.
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#projections
Where a Projection is a 'closed' projection (a projection interface whose accessor methods all match properties of the target aggregate) then the documentation notes that additionally:
Spring Data can optimize the query execution [to select only the relevant fields], because we know about
all the attributes that are needed to back the projection proxy
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#projections.interfaces.closed
Spring Data also allows for Projections to be specified dynamically at runtime. See further:
https://github.com/spring-projects/spring-data-commons/blob/master/src/main/asciidoc/repository-projections.adoc#dynamic-projections
First mark your relations as LAZY
Then specify what data needs to be fetched on a per-query basis.
See for example:
https://vladmihalcea.com/eager-fetching-is-a-code-smell/
I have an entity that has simple String columns as well as many ElementCollections (List and Map). I noticed looking at my postgres logs that PostGres when querying for this entity is doing a bunch of SELECT queries consecutively to get all the ElementCollections.
For efficiency, I would imagine doing one SELECT query with some inner JOINs might be better to avoid all of the individual SELECT queries. Is there a way to do that without writing a very verbose select query manually with all the INNER JOINs?
I have been looking around FetchTypes and Spring QueryData language, and DTO Projection but I imagine there might be a more straightforward way. The benefit I had been taking for granted is by explictly doing the JOINs if I add a new field then I will have to keep updating my query and if Spring is generating queries for me, then I wouldn't have to do anything.
// Person.java
#Entity
public Person {
#Id
long personId;
#Column
String firstName;
#Column
String lastName;
#ElementCollections
Set<String> someField;
#ElementCollections
Map<String, String> otherField;
#ElementCollections
Set<String> anotherField;
#ElementCollections
Map<String, String> yetAnotherField;
}
What is happening right now is
SELECT firstName, lastName FROM Person WHERE personId=$1
SELECT someField FROM Person_SomeField WHERE someField.personId=$1
SELECT otherField.key otherField.value FROM Person_OtherField WHERE otherField.personId=$1
And this continues for all of the ElementCollections tables which leads to a lot of queries.
Change your annotation to #ElementCollection(fetch = FetchType.EAGER).
It sounds like those fields are being lazily loaded (Hibernate is waiting until they are accessed to load them) which results in the N+1 queries you are seeing. LAZY loading is the default behavior for this type of member, which makes sense because loading it is not cheap. However, if you always want these members loaded, setting it to EAGER can make sense. Setting the fetch to EAGER will force Hibernate to load them along with the entity itself. This is the documentation for the fetch option on #ElementCollection:
(Optional) Whether the collection should be lazily loaded or must be
eagerly fetched. The EAGER strategy is a requirement on the
persistence provider runtime that the collection elements must be
eagerly fetched. The LAZY strategy is a hint to the persistence
provider runtime.