Is there a way to fetch a class with associated classes in a single SELECT query in Spring Data JPA? - spring-boot

I have two classes, A and B with a One-To-Many relationship.
#Entity
public class A {
//some code
#OneToMany(fetch = FetchType.LAZY, mappedBy = "abc")
private List<B> b;
}
I have a JPA Repository for A, and I observed that when I fetch an A from the database with a repository method, Bs are not included. When I want to access Bs, additional SELECT queries are executed to fetch associated Bs(if there are 100 associated Bs, 100 additional queries are executed). making FetchType.EAGER only changes when these additional SELECT queries are executed. i.e. they are called right after the main SELECT query. Either way, additional SELECT queries are executed to fetch associated classes.
Is this natural behavior? I found that JPA Entity Graphs is the solution for this issue/to fetch A with Bs with a single SELECT query. Are there any other ways to address this issue? The problem with #EntityGraph is it has to be annotated with each repository method separately. Also, is there a way to annotate #EntityGraph once so it affects all the methods in the Repository?
I'm using Spring Boot 2.5.1. Thanks in advance!

Related

I am using Spring boot jpa with Restful api services to insert multiple users in array or list

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)

Using Spring Query Methods JPA to efficiently query DB without multiple SELECT statements

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.

join more than one table in spring jparepository

I am trying to fetch record by doing a join. I am new to spring jparepository.
I understand that there is separate repository for each entity(table) where when i implement i need to define the entity and datatype of primary key.
Could anyone please suggest how can I fetch record by joining two tables.
I have two repo as below:
public interface AEntityRepository extends JpaRepository<AEntity, Integer>
public interface BEntityRepository extends JpaRepository<BEntity, Integer>
I want to join above two entity(AEntity, BEntity).
I know I can have custom query using something like below:
#Query("SELECT ****** FROM AEntity ae")
AEntity findCustomrRecords();
However can I write the same kind of query (join query) with join.
Do i need to have a separate repository implementing some other class.
Can anyone please help.
I am using mysql.
I understand that there is separate repository for each entity(table)
This is a very common misunderstanding. You do not want to have a repository per entity, but per aggregate root. See http://static.olivergierke.de/lectures/ddd-and-spring/
Regarding your specific problem at hand: Creating a custom method in your repository interface and annotating it with a JPQL should do the trick. So you get something like:
#Query("select a from BEntity b join b.a a where b.foo = :foo")
AEntity getAllFooishAs(String foo);
You can use any join syntax JPQL offers in the query.

How to limit the results of a Spring Repository with custom query

I am using a Spring repository to query a database, but because of the nature of my application I need to use a custom #Query in order to JOIN FETCH lazy collections.
This process works fine, but now I need to limit the result to a single record. I understand that Spring has the notion of findFirst or findTop1 in the method names, but this does not appear to work when you have a custom query.
How can I use a custom query and limit the result to 1 record when using a Spring repository?
you need to pass a Pageable param in your query method
#Query("select e from Entity e LEFT JOIN FETCH e.list")
public Page<Entity> find(Pageable pageable);
and call the method passing the object
repository.find(new PageRequest(0, 1));

JPA / JTA / #Transactional Spring annotation

I am reading the transaction management Using Spring framework. In first combination I used Spring + hiberante and used Hibernate's API's to control the transaction (Hibenate API's). Next, I wanted to test using #Transactional annotation, and it did work.
I am getting confused on:
Do JPA , JTA, Hibernate have their "own" way of transaction
management. As an example, consider if I use Spring + Hibernate, in
that case would u use "JPA" transactions?
Like we have JTA, is it true to say we can use Spring and JTA to
control transactions?
The #Transactional annotation, is that specific to Spring
Framework? From what I understood, this annotation is Spring
Framework specific. If this is correct, is #Transactional using
JPA/JTA to do the transaction control?
I do read online to clear my doubts, however something I don't get direct answer. Any inputs would be great help.
#Transactional in case of Spring->Hibernate using JPA i.e.
#Transactional Annotations should be placed around all operations that are inseparable.
So lets take example:
We have 2 model's i.e. Country and City.
Relational Mapping of Country and City model is like one Country can have multiple Cities so mapping is like,
#OneToMany(fetch = FetchType.LAZY, mappedBy="country")
private Set<City> cities;
Here Country mapped to multiple cities with fetching them Lazily.
So here comes role of #Transactinal when we retrieve Country object from database then we will get all the data of Country object but will not get Set of cities because we are fetching cities LAZILY.
//Without #Transactional
public Country getCountry(){
Country country = countryRepository.getCountry();
//After getting Country Object connection between countryRepository and database is Closed
}
When we want to access Set of Cities from country object then we will get null values in that Set because object of Set created only this Set is not initialize with there data to get values of Set we use #Transactional i.e.,
//with #Transactional
#Transactional
public Country getCountry(){
Country country = countryRepository.getCountry();
//below when we initialize cities using object country so that directly communicate with database and retrieve all cities from database this happens just because of #Transactinal
Object object = country.getCities().size();
}
So basically #Transactional is Service can make multiple call in single transaction without closing connection with end point.
Hope this will helpful to you.

Resources