join more than one table in spring jparepository - spring

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.

Related

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

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!

How to Write Spring Data JPA query for getting two counts after group by

I have a table like this
I want to write something like this
SELECT oi.order_id,
COUNT(oi.found) as found,
(COUNT(1) - COUNT(oi.found)) as not_found
FROM orders_items oi
WHERE oi.order_id = 43
GROUP BY oi.order_id
Is it possible to write a query like this in Spring Data JPA?
Yes you can,
You need to have an interface annotated with #Repository and that extends the JpaRepository. There you can create queries, when the out of the box syntax does not cover your needs you can annotate a method with #Query and write your query likes this.
#Query("SELECT oi.order_id FROM order_items oi ...")
List<MyEntityClass> findMyEntities()
You can pass parameters to use also in the method. The syntax is not identical with the native one because jpa offers some abstraction. For small examples you can look here: https://www.baeldung.com/spring-data-jpa-query

Fetch jpa sql execution plan with #QueryHint and spring data repository

I am using spring-data for DB interaction. I want to see the jpa sql execution plan for a query written in repository. How can i do it.
https://vladmihalcea.com/execution-plan-oracle-hibernate-query-hints/ tells about using GATHER_PLAN_STATISTICS and COMMENT query hints. I added COMMENT hint but don't know how to add other one.
public interface StudentRepository extends JpaRepository<Student, Long>{
#QueryHints({
#QueryHint(name=org.hibernate.annotation.queryHints.COMMENT,
value="SQL_PLAN_STUDENT")
})
List<Student>findByStudentIDIn(List<Long> ids);
}
The #QueryHints annotation accepts an array constructor like list of #QueryHint items.
So you can add multiple QueryHints by addings them to a comma separated list. For example:
#QueryHints({
#QueryHint(name=org.hibernate.annotations.QueryHints.COMMENT, value="SQL_PLAN_STUDENT"),
#QueryHint(name="GATHER_PLAN_STATISTICS" , value="GATHER_PLAN_STATISTICS")
})
Unfortunately I don't have access to a running instance of a oracle dbms, so I can't check the result of the given hint.

How to write a Custom JPA method to search a database record using fields name

Here i am working in Spring Boot. Now i am creating API's for CRUD Operations. Also i need to write a code for Searching the database record using fields name. Here i am working with "Products" table. the table contains fields like "itemCode", "hsCode", "itemCategoryId","productDescription","brand","countryOfOrigin","uom","retailSellingPrice","exciseTaxPercentage","assignedTo","assignedBy",...etc.
So, if the user gives the input as the brand, uom, retailSellingPrice. i should use a Query like "SELECT * FROM PRODUCTS WHERE brand=:brand, uom =:uom,retailSellingPrice=:retailSellingPrice ".
I write a Custom JPA method like findByuomContainingOrRetailSellingPriceContainingOrBrandContaining(parameter1, parameter2, parameter3);
But is there any other approach to search the products using fields so that if 10 searching fields is there, then my custom method will be small only.
Please give me some suggestions
You can create your own custom repository and give method name whatever you want(a small one).
You can create a custom repository like below :
Assuming that you have a ProductRepository implements CrudRepository<Product,Long>
Create an interface like #Your_repository_name{custom} (ProductRepositoryCustom) and give method name whatever you want with required parameters.
Create implementation class for ProductRepositoryCustom interface. You can name it whatever you want, but it will be good if you follow some convention. Do it like #Your_repository_name{Impl} (ProductRepositoryImpl)
Extend ProductRepositoryCustom from ProductRepository(ProductRepository implements CrudRepository<Product,Long>,ProductRepositoryCustom)
Now you can call method of ProductRepositoryImpl from the same object you call the methods of ProductRepository.
#Autowired
private ProductRepository productRepository;
Use productRepository to call methods of Impl clas.
Take a look at JPA's Query by Example. QueryByExampleExecutor interface is extended by JpaRepository. It has a few methods for searching by example. Here is a simple example,
Let say Product is an entity representing Products table, then you can do something like this,
Product product = new Product();
product.setItemCode(...);
product.setHsCode(...);
...
Example<Product> example = Example.of(product);
Iterable<Product> = repository.findAll(example);
You can find a concrete example here.

FetchTypes in Spring Data JPQL Query (MultipleBagFetchException)

I am using Spring Data and defining following query:
#Query("SELECT u FROM AppUser u LEFT OUTER JOIN fetch u.userRights a LEFT OUTER JOIN fetch u.userGroups g LEFT OUTER JOIN fetch u.userGroups ug LEFT OUTER JOIN FETCH ug.groupRights where u.login = :login")
public Optional<AppUser> findOneWithCompleteRights(#Param("login") String login);
As you might see, I want to get back the logged in user with all his access rights. While starting the spring application, it runs into:
Caused by: javax.persistence.PersistenceException: org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags
I have checked following:
Multiple fetches with EAGER type in Hibernate with JPA
If I change all#XXXToMany Types to java.util.Set, it works, but I would like to decide the type on my own...
The other annotations of linked solution (see bottom) seem to be ignored if attached to the #Query method. Second would not make sense, anyway.
Load each collection separately using subselect #Fetch(FetchMode.SELECT)
Force usage of list instead of bag by adding index column #IndexColumn(name="LIST_INDEX")
Does anybody have another solution rather than setting the type to Set?
I had that problem also.
It happens when the class to load has more than on property of type List mapped.
You can resolve that,
by changing the type of
AppUser.userRights and AppUser.userGroups
from java.util.List to java.util.Set.
Not using Set here instead of List is exactly what Vlad Mihalcea is describing in this post and in some answers on StackOverflow. In his post he says to use separate queries.
But he is giving the solution not with the #Query-Annotation provided by the Spring-Data Project rather using JPQL-statements and the entityManager.
So to achieve the separate Query-Execution I would have thought, that the #Fetch(FetchMode.SELECT) (or SUBSELECT, not yet sure about the difference) would be a proper solution. But not for the #Query-Annotation but for the attribute in the class.
So in your case maybe:
class AppUser {
....
#OneToMany
#Fetch(FetchMode.SELECT)
List<UserRights> userRights
....
}
But trying that in my own project did not work, either. So another solution might be to somehow create multiple queries in the Statement of the #Query-Annotation, to act according Vlad's suggestion Not sure if that is possible in the Annotation-Parameter itself or if there has to be two Methods with two annotations.
#Query(
"SELECT u FROM AppUser u
LEFT OUTER JOIN fetch u.userRights a
LEFT OUTER JOIN fetch u.userGroups g
LEFT OUTER JOIN fetch u.userGroups ug
LEFT OUTER JOIN FETCH ug.groupRights where u.login = :login"
)
public Optional<AppUser> findOneWithCompleteRights(#Param("login") String login);

Resources