Is it possible to #Query two microservice databases in Java? - 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();

Related

Complicated query with jparepository. Three tables join

I want to filter entities with next way:
get distinct 10 top disciplines, which are ordered by students count(attendance) for sessions between some period of time.
Discipline has List<Session> sessions;//bidirectional
Every Session has its own List<Student> students;//bidirectional
So, Student didn't know anything about Discipline, only via Session.
And I want to write using Spring JpaRepository something like:
List<Discipline> findTop10DisciplinesDistinctOrderBySessionsStudentsCountAndBySessionsBetween(Date from, Date to);
but there are some restrictions. It didn't work for me
No property count found for type Student! Traversed path:
Discipline.sessions.students.
Query looks like this(mysql):
select d.*
from session as ses
inner join
(select st.*
from student as st
inner join session as ses on ses.id = st.session_id
where ses.time > (curdate() - interval 30 day)
group by st.session_id
order by count(st.id) desc
limit 10) as st2
on ses.id = st2.session_id
inner join discipline as d on ses.discipline_id = d.id
But how to add this query to jpa repository?
Derived queries, those that get created from the method name are not suitable for use cases as yours. Even if it would work it would result in an unwieldy method name. Use an #Query with JPQL or SQL query instead.

Spring data jpa from multiple tables

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.

Return custom object from Spring Data with Native Query

My question is based on another post. How can I achieve the same with a native query? Native queries do not allow JPQL thus do not allow new instances either.
My POJO.
class Coordinates {
private final BigDecimal latitude
private final BigDecimal longitude
...
}
My database table contains coordinates for cities perimeter, so there are three columns: city_name, latitude, longitude. Each city contains lots (really, LOTS) of perimeter coordinates that will be used to build a shadow area in Google Maps.
I intend to build a simple native query on that table that should return a list of coordinates.
Found the answer on another post. Basically I used SqlResultSetMapping along with ConstructorResult (no other way worked out) with a special attention to a comment on the accepted answer of the mentioned post: you need to add the #NamedNativeQuery annotation to the entity of the used interface AND prepend the entity's name with a . otherwise it won't work.
Example:
#Entity
#Table(name = "grupo_setorial")
#SqlResultSetMapping(
name = "mapeamentoDeQuadrantes",
classes = {
#ConstructorResult(
targetClass = Coordenada.class,
columns = {
#ColumnResult(name = "latitude"),
#ColumnResult(name = "longitude")
}
)
}
)
#NamedNativeQuery(
name = "GrupoCensitario.obterPerimetroDosSetores",
query = "SELECT latitude as latitude, longitude as longitude FROM coordenadas where id_setor IN (:setores)",
resultSetMapping = "mapeamentoDeQuadrantes"
)
public class GrupoCensitario {
This is https://jira.spring.io/browse/DATAJPA-980 and Here is a project that demonstrates the issue.
#Query(value = "SELECT name AS name, age AS age FROM Person", nativeQuery = true)
List<PersonSummary> findAllProjectedNativeQuery();
It is fixed in the Spring Data JPA 2.0 GA (Kay) release which comes with Hibernate 5.2.11.
The issue is also fixed for Spring Data 1.10.12 (Ingalls) and 1.11.8 (Hopper) but will need to be run on Hibernate 5.2.11 to work.
You will have to use sql result set mapping which is part of JPA.
If you are using a recent version of spring-data and also making use of the Repositories, I personally think that the answer from Itsallas leads to the right solution.
I actually did't now about (Spring Data) Projections yet and needed a moment to understand what he was showing in his example.
Therefore I just want to add a link to the Spring Data JPA - Reference Documentation, have a look at the Projections chapter.
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.
The answer I found:
public interface UserEventRepository extends JpaRepository<UserEvent, Long> {
List<UserEvent> findAllByUserId(Long userId);
#Query(value = "SELECT user_id FROM user_event ue " +
"WHERE ue.user_id = :userId", nativeQuery = true)
List<Long> findUserIdByEventId(#Param("userId") Long userId);
}
That way we return List of Long - list of ids. The key here is that we are setting the nativeQuery property to true. The value itself is the query we want to be executed.
I hope that helps. It seems a clear solution.
The projections solutions was the best. (query by id just an example, you can just use extends CRUD Operations)
Just add the Interface as response to the query as
Example repository :
#Query(select * from tableA where tableA = :id)
DisplayLangLongI findTableAbyId(#Param(value = "id") Long id)
Example Interface (DisplayLangLongI.java)
public interface DisplayLangLongI () {
BigDecimal getLatitude();
BigDecimal getLongitude();
...... (you can add more)
}
In interface, you can select which parameter/object just to display

left join with spring data jpa and querydsl

I am using spring data jpa and querydsl and trapped on how to write simple nice query to left join two tables.
Suppose I have an Project entity and a Task entity with OneToMany relationship defined in Project, I would like to do something like:
select * from project p left join task t on p.id = t.project_id where p.id = searchTerm
select * from project p left join task t on p.id = t.project_id where t.taskname = searchTerm
In JPQL, it should be:
select distinct p from Project p left join p.tasks t where t.projectID = searthTerm
select distinct p from Project p left join p.tasks t where t.taskName = searthTerm
I have a ProjectRepository interface, which extends JpaRepository and QueryDslPredicateExecutor.
That gives me access to method:
Page<T> findAll(com.mysema.query.types.Predicate predicate, Pageable pageable)
I know that left join can be easily achieved by creating a new JPAQuery(entityManager). But I do not have entity manager explicitly injected with spring data jpa.
Is there nice and simple way to build a predicate with left join?
Wish someone here have experienced this and is able to give me an example.
Thank you.
Frey.
If you want to express a constraint on tasks then you can do it like this
QProject.project.tasks.any().id.eq(searchTerm)
If you want to express preloading of certain tasks instead via a left join you can't express that via a Predicate. A Predicate in Querydsl is a boolean expression for the where, join-on and having parts of the query.

Hibernate: Query By Example equivalent of association Criteria Query

I'd like to search my data source for all object instances based on the values of an object related by association. The data model can be simplified to: object of type A holds a list of objects of type B. The goal is to find all instances of A where A contains a B such that B has a property value of X.
I can already successfully achieve this using Criteria queries as follows:
List<A> results = session.createCriteria(A.class)
.createCriteria("listOfBs")
.add(Restrictions.eq("propertyInB", x))
.list();
This is a simplification, and multiple properties of B will apply - the search functionality is necessary for a user populated filter.
I would like to replace this approach with query by example - where I'd simply create an object graph with the desirable parameters. My attempt in following the Hibernate docs failed, and is described in this question.
I thought that it might be helpful to demonstrate what I'm trying to achieve in a manner that works, and then seek equivalents - that's why I'm re-asking the question.
In short, my question is: How would you implement the above Criteria Query as a Query by Example in Hibernate? I'm using Hibernate 3.6.6.
Thanks!
Suppose you want to do something like :
Select a.* , b*
from a join b on a.id = b.id
where a.property1 = "wwww"
and a.property2="xxxx"
and b.property1="yyyy"
and b.property2="zzzz"
To implement the above query using Query by Example(QBE):
/***Initialize an instance of Class A with the properties that you want to match***/
A instanceA = new A();
instanceA.setProperty1("wwww");
instanceA.setProperty2("xxxx");
Example exampleA = Example.create(instanceA);
/***Do the same for the Class B**/
B instanceB = new B();
instanceB.setProperty1("yyyy");
instanceB.setProperty2("zzzz");
Example exampleB = Example.create(instanceB);
/**Create and execute the QBE***/
List<A> results = session.createCriteria(A.class)
.add(exampleA)
.createCriteria("b",CriteriaSpecification.LEFT_JOIN) // b is the property of Class A
.add(exampleB)
.list();
The result is already fetch-joined , which means the collection instance B in the A is already fully initialized.

Categories

Resources