Spring data jpa from multiple tables - java

I am using spring data jpa. And I have a inner join on two tables. This is my query.
SELECT A.NAME, A.CARD_NUMBER, A.ADDRESS, A.EMAIL FROM USER_INFO ABC INNER JOIN USR_DETAIL DEF ON (ABC.ID = DEF.ID) WHERE ABC.ID = '123456';
The two table here have no relationship. So one-to-one or many-to-one or many-to-many on the column name doesn't make sense. Can I define entities without relationship? The reason why we are doing a inner join on the two tables here is simply because doing a join on both of them will be a expensive query.

You can define both entities without any kind of relationship and then you can retrieve the data specifying nativeQuery=true in the #Query(..) annotation in the read method.
#Query(value = "SELECT ABC.NAME, ABC.CARD_NUMBER, ABC.ADDRESS, ABC.EMAIL " +
"FROM USER_INFO ABC " +
"INNER JOIN USR_DETAIL DEF ON (ABC.ID = DEF.ID) " +
"WHERE ABC.ID = :id", nativeQuery = true)
UserInfoDetails retrieveUserInfoAndDetailById(#Param("id") String id);
Side notes:
In the projection of the query, I correct the alias from A to ABC as the query was not written correctly. Feel free to edit the projection accordingly to your needs.
As a return type, I wrote a UserInfoDetails class, supposing it will be return something similar. Feel free to change it accordingly to your needs.

Related

Is it possible to #Query two microservice databases in Java?

I am trying to write a query where conditions in two micro-service application databases will be applied to retrieve data. Is it possible to write a #Query within a repository to do so, or will I need to do it from a service or any other method? With the current functions below I get an error. Any code examples or reference articles will be truly appreciated.
Below I have showed my controller function and repository query.
Controller Function:
#GetMapping("/orders/query/test/")
public List<Orders> findAllOrdersWhereCondition(){
log.info("Start of findAllOrdersWhereCondition method");
return repository.findAllActiveAndUnrespondedQueriesForHelp();
}
Repository Functions:
#Query("SELECT g FROM ORDERS g INNER JOIN operators o ON g.profileToId = o.id OR g.profileFromId = o.id WHERE g.active = true and g.responded = false AND o.operatorType = 1 ")
List<Orders> findAllActiveAndUnrespondedQueriesForHelp();
Is it one service talking to two databases, or two services each talking to their own individual databases?
If it's the former, and the databases are relational and ACID, you can do a JOIN and a single query.
If it's the latter, you have to make two HTTP requests, one to each service. They don't know about each other. You've probably given up ACID in this case.
It's hard to give a correct answer without error message and entity-classes of your application. But I think, that you made a mistake in the table names in your query - if you use JPQL, you need to observe the register of entity class names writing the query. In your case it's maybe:
#Query("SELECT g FROM Orders g INNER JOIN Operators o ON g.profileToId = o.id OR g.profileFromId = o.id WHERE g.active = true and g.responded = false AND o.operatorType = 1 ")
List<Orders> findAllActiveAndUnrespondedQueriesForHelp();
If you want to make a query to a database in pure SQL, you need to set true to the field nativeQuery. For example:
#Query("SELECT g FROM Orders g INNER JOIN Operators o ON g.profileToId = o.id OR g.profileFromId = o.id WHERE g.active = true and g.responded = false AND o.operatorType = 1 ", nativeQuery = true)
List<Orders> findAllActiveAndUnrespondedQueriesForHelp();

Join fetch fails on fetching 3rd level relationship

I have three entities: Person, Country and CountryTranslation.
Person is related to one Country and Country have many CountryTranslations.
I want my query to fetch both Country and CountryTranslations when it fetches a Person in order to avoid multiple queries.
To bring the Country along with Person I do:
List<Person> persons = (List<Person>) entityManager
.createQuery("SELECT person from Person person " +
"left join fetch person.country")
.getResultList()
This works fine, I see on hibernate it is fetching nicely and no extra queries are executed to bring Country, but to bring CountryTranslations it still execute extra queries. Then I tried:
List<Person> persons = (List<Person>) entityManager
.createQuery("SELECT person from Person person " +
"left join fetch person.country " +
"left join fetch person.country.translations")
.getResultList()
And I get the error:
org.hibernate.QueryException: query specified join fetching, but the owner of the fetched association was not present in the select list
What is the right way to do this fetching?
Thanks in advance
You correct this giving an alias for each relationship.
SELECT person
FROM person person
LEFT JOIN FETCH person.country country
LEFT JOIN FETCH country.translations
It's a framework's "limitation": When you use linked fetchs you should to give an alias for each relationship!
This behavior can also be explained because will be difficult to understand what these linked fetches really mean: Does the framework will fetch each relationship or only the last one? It's more simple to just tell to the framework what fetch relationship you want.

Map sql query result to java object(in Non-Entity class) using spring jpa

I want to assign SQL query result to Java object which is in non-entity class.
My query is counting the number of records in Table A mapped to another Table B.
#Query(value="select count(a.id) from table1 a join table2 b on a.id=b.id group by a.id", nativeQuery=true)
Non-Entity class
public class Sample {
//assign query result to count variable
private long count;
// getters and setters
}
A and B are Entity class, I'm selecting specified columns of Entity A and B and including that columns in Sample.class and sending data as JSON on REST call.
Now my question is to assign count result to count variable.
Thanks in advance
How to do a JPQL query using a "group by" into a projection (Non-Entity-Class)?
Scenario you have two tables: User and User_Role and you want to know how many users in your system has the "public" role and how many have the "admin" role (Any other roles too if present).
For example: I want a query that will let me know there are two users that have "public" role and one user has the "admin" role.
Simplest Example:
#Query("SELECT ur.roleName, count(u.id) from User u left join u.userRole ur group by ur.roleName")
List<Object[]> getCounts();
In this case dealing with the result is more complicated then you typically would want. You would have to iterate over both the list and array of Objects.
Query into a projection Example:
#Query("SELECT new com.skjenco.hibernateSandbox.bean.GroupResultBean(ur.roleName, count(u.id)) from User u left join u.userRole ur group by ur.roleName")
List<GroupResultBean> getCountsToBean();
This would give you a List that is much better to work with.
Code Example: https://github.com/skjenco/hibernateSandbox/blob/master/src/test/java/com/skjenco/hibernateSandbox/repository/UserProjectionExampleTest.java

Converting SQL query with joins to JPA

I have this SQL query:
select ts.scorename from content_package cp
join content_package_content_package_components cpcps on cpcps.content_package = cp.id
join content_package_component cpc on cpc.id = cpcps.content_package_components
join tests t on t.id = cpc.assessment
join test_scores ts on ts.tests_id = t.id
where cp.tag = 'C_TS_EN_ABSA_G_'
And want to convert it to JPA, ideally Specifications - is this possible?
you can write this query in JPQL but firs you need to create POJO class of your models. if you are using Intelij idea you can create your models in it by going to persistence section ,right click on your data source and select generate persistence mapping by (hibernate or database schema). after creating models you should change your table names to pojo classes in query and so on ....

getting result set into DTO with native SQL Query in Hibernate

I have a query like below
select f.id, s.name, ss.name
from first f
left join second s on f.id = s.id
left join second ss on f.sId = ss.id
If I could use HQL, I would have used HQL constructor syntax to directly populate DTO with the result set.
But, since hibernate doesn't allow left join without having an association in place I have to use the Native SQL Query.
Currently I am looping through the result set in JDBC style and populating DTO objects.
Is there any simpler way to achieve it?
You could maybe use a result transformer. Quoting Hibernate 3.2: Transformers for HQL and SQL:
SQL Transformers
With native sql returning non-entity
beans or Map's is often more useful
instead of basic Object[]. With
result transformers that is now
possible.
List resultWithAliasedBean = s.createSQLQuery(
"SELECT st.name as studentName, co.description as courseDescription " +
"FROM Enrolment e " +
"INNER JOIN Student st on e.studentId=st.studentId " +
"INNER JOIN Course co on e.courseCode=co.courseCode")
.addScalar("studentName")
.addScalar("courseDescription")
.setResultTransformer( Transformers.aliasToBean(StudentDTO.class))
.list();
StudentDTO dto =(StudentDTO) resultWithAliasedBean.get(0);
Tip: the addScalar() calls were
required on HSQLDB to make it match a
property name since it returns column
names in all uppercase (e.g.
"STUDENTNAME"). This could also be
solved with a custom transformer that
search the property names instead of
using exact match - maybe we should
provide a fuzzyAliasToBean() method ;)
References
Hibernate Reference Guide
16.1.5. Returning non-managed entities
Hibernate's Blog
Hibernate 3.2: Transformers for HQL and SQL

Categories

Resources