Class A and Class B are entities mapped to their own database tables. Class C is NOT mapped and contains all the attributes of A and B. Is it possible to build a HQL to populate C?
Yes, you can. You can use Hibernates ResultTransformer for this:
List resultWithAliasedBean = s.createQuery(
"select e.student.name as studentName," +
" e.course.description as courseDescription" +
"from Enrolment as e")
.setResultTransformer( Transformers.aliasToBean(StudentDTO.class))
.list();
StudentDTO dto = (StudentDTO) resultWithAliasedBean.get(0);
Related
I wrote this JPQL query and expect a result as List<Question>:
#Query("SELECT q FROM Question q WHERE q.id IN (SELECT qc.questions FROM QCard qc WHERE qc.id IN (SELECT ct.qCards FROM CTest ct WHERE ct.id=:id))")
These are my classes:
class CTest {
id, List<QCard>
}
class QCard{
id, List<Question>
}
class Question{
id
}
I expected all questions as return for given CTest.id.
But I got a compiler-error with message:
SQLSyntaxErrorException
I tried use ":" before "select" words but it had not helped.
What is wrong?
Test your SQL query in an SQL-client (e.g. Squirrel, DbVisualizer, etc.).
Assuming your foreign keys are named:
question_id in table QCard
card_id in table CTest
you could have an SQL with subselects like:
SELECT q.id
FROM Question q
WHERE q.id IN (
SELECT qc.question_id
FROM QCard qc
WHERE qc.id IN (
SELECT ct.card_id
FROM CTest ct
WHERE ct.id = 1 -- example test id
)
)
Does it return the expected result or are there syntax errors?
Then subsequently replace your subselects by JOINs.
Question and Cards
SELECT q.id, c.id
FROM Question q
JOIN QCard c ON c.question_id = q.id
Cards and Tests
SELECT c.id, t.id
FROM QCard c
JOIN CTest t ON t.card_id = c.id
All together
SELECT q.id, c.id, t.id
FROM Question q
JOIN QCard c ON c.question_id = q.id
JOIN CTest t ON t.card_id = c.id
Note: add WHERE clauses like WHERE t.id = 1 if needed.
Experiment with the FROM/JOIN order as it makes sense.
Then translate the running SQL query to JPQL. For example:
#Query("SELECT q"
+ " FROM CTest test"
// a test has many cards (1:n)
+ " JOIN QCard card ON card.id = test.card_id" // associated cards
// a card has many questions (1:n)
+ " JOIN Question q ON q.id = card.question_id" // associated questions
+ " WHERE test.id = :id")
public List<Question> findQuestionsByTestId(String id);
List<Question> findByIdIn(List<Long> idList); //In repository
or
String qlString = "select i from Item i where i.name IN :names";
Query q = em.createQuery(qlString, Item.class);
List<String> names = Arrays.asList("foo", "bar");
q.setParameter("names", names);
List<Item> actual = q.getResultList();
I did those example in my past work, check it, tnx
In your existing query, in inner queries you are selecting entities and checking IN against Id, which will definitely won't work. As you can't complete entry with the Id.
As you haven't shared your complete entity structure, assuming that you have two way relationship declared correctly in entities, here I am placing a reference query which uses the join:
#Query("SELECT q FROM Question q JOIN q.qCard qc WHERE q.qCardId = qc.id AND qc.cTestId = :id")
Where qCardId is the foreign key reference of QCard entity in Question entity and cTestId is the foreign key reference of CTest entity in QCard entity.
You can use this for your reference to update your query with joins.
I am assuming a setup as described in: https://howtodoinjava.com/hibernate/hibernate-one-to-many-mapping-using-annotations/
Employee:
#JoinColumn(name="EMPLOYEE_ID")
private Set<AccountEntity> accounts;
Account:
#ManyToOne
private EmployeeEntity employee;
Using JPA/Hibernate, how can I fetch results using a WHERE condition that applies to Account. In other words, query something like Select all employees with accounts with sales > 0 or similar.
I'm assuming sales column as INT in account table.
you can write a query like following:
TypedQuery<Employee> query = em.createQuery("SELECT e FROM Employee e JOIN Account a ON e.id = a.accounts.employee_id WHERE a.sales > :sales", Employee.class);
query.setParameter("sales", salesInput);
List<Employee> items = query.getResultList();
I would recommend you to go through this tutorial to learn about CRUD operations in Hibernate Associations
https://www.dineshonjava.com/spring-crud-example-using-many-to-one/
The Spring Data Jpa Method like this:
#Query("select pb.id,pp.max_borrow_amt,pp.min_borrow_amt
from product_loan_basic pb left join product_loan_price pp on pb.code=pp.product_code
where pb.code IN(?1) and pb.status='publish' order by ?2 ",
nativeQuery = true)
List<Object[]> findByCodesIn(List<String> codes,String orderby);
then order by is " max_borrow_amt desc ", but this is invalid.
the List is disordered.
Dynamic sorting in Spring Data JPA
If you used a JPA query you could use Sort as an argument of your query method to define the sorting order:
#Query("select m from Model m")
List<Model> getSortedList(Sort sort);
and then, for example:
List<Model> models = getSortedList(Sort.by(Sort.Direction.DESC, "name"));
But Spring Data JPA can't use Sort with native queries:
Spring Data JPA does not currently support dynamic sorting for native queries, because it would have to manipulate the actual query declared, which it cannot do reliably for native SQL.
However you can use Pageable and its implementation PageRequest instead:
#Query(value = "select m.name as name from models m", nativeQuery = true)
List<ModelProjection> getSortedList(Pageable p);
and then:
List<ModelProjection> modelNames = getSortedList(PageRequest.of(0, 1000, Sort.Direction.DESC, "name"));
P.S. Instead of array of Objects as returned parameters, it's better to use projections, for example:
public interface ModelProjection {
String getName();
}
Note that in this case the good practice is to use aliases in queries (ie m.name as name). They must match with correspondent getters in the projection.
Working demo and test.
Thanks everyone!
My problem has been solved.
If you want to use Spring data jpa nativeQuery & Sort, you should do like this:
#Query(
value ="select pb.id,pp.max_borrow_amt from product_loan_basic pb left join product_loan_price pp on pb.code=pp.product_code ORDER BY ?#{#pageable} ",
countQuery = "select count(*) from product_loan_basic",
nativeQuery = true
)
Page<Object[]> findAllProductsAndOrderByAndSort(Pageable pageable);
?#{#pageable} is required and countQuery is required.
Pageable pageable = new PageRequest(0,1000,Sort.Direction.DESC,"id");
then the result is sorted.
See Spring Data and Native Query with pagination.
org.hibernate
hibernate-core
4.3.8.Final
org.hibernate
hibernate-entitymanager
4.3.8.Final
My pom.xml
My Problem is: How to make a query like this...
SELECT
TABLE_D.*,
TABLE_A.NAME_A
FROM
TABLE_D
INNER JOIN
TABLE_E
ON TABLE_D.ID_TAB_E = TABLE_D.ID_TAB_D
LEFT JOIN
TABLE_C
ON TABLE_C.ID_TAB_C = TABLE_D.ID_TAB_D
INNER JOIN
TABLE_B
ON TABLE_B.ID_TAB_B = TABLE_C.ID_TAB_C
INNER JOIN
TABLE_A
ON TABLE_A.ID_TAB_A = TABLE_B.ID_TAB_B
WHERE
TABLE_A.NAME_A = "XXXX";
And Return the selected the values TABLE_D and TABLE_A in a unique Object List(ex: Object that i create to take all this fields) (I could create 1 filter, whatever...) in the JPA ? Plz Help.
If you need to return a list of selected columns in HQL you can just write your hql query and return a List of Object array, i.e.:
List<Object[]> result = session.createQuery("select a.field1, b.field2 from EntityA a join a.entityB b").list();
then you can iterate and get values, based on their type (i.e. String):
for (Object[] arr : result) {
String col1 = (String)arr[0];
String col2 = (String)arr[1];
}
I have two entities Customer and Order in a one-to-many relation.
For each customer I need to count the number of associated orders and sort the results by this number.
In a native postgres query it looks like this:
select cust.id, count(order.id) from customers cust
left outer join orders order
on cust.id = order.customer_id
where .... conditions ...
group by cust.id
order by count desc;
But I must do this using CriteriaBuilder because this query is part of a larger piece of code that uses CriteriaBuilder to put in additional conditions. In Hibernate I would have probably used Projections, but I can't find anything similar in JPA.
Any help in composing the query using CriteraBuilder would be much appreciated.
Thank you in advance.
Supposing that the entity Customer has a OneToMany property like this:
#OneToMany(mappedBy = "customerId")
private Collection<Order> orders;
You can use the following query:
EntityManager em; // to be built or injected
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Tuple> cq = cb.createTupleQuery();
Root<Customer> customer = cq.from(Customer.class);
CollectionJoin<Customer, Order> orders = customer.join(Customer_.orders, JoinType.LEFT);
cq.select(cb.tuple(customer, cb.count(orders)));
cq.where(... add some predicates here ...);
cq.groupBy(customer.get(Customer_.id));
cq.orderBy(cb.desc(cb.count(orders)));
List<Tuple> result = em.createQuery(cq).getResultList();
for (Tuple t : result) {
Customer c = (Customer) t.get(0);
Long cnt = (Long) t.get(1);
System.out.println("Customer " + c.getName() + " has " + cnt + " orders");
}
The above approach uses Metamodel. If you don't like it, you can replace Customer_.orders with "orders" and Customer_.id with "id".
If the OneToMany property is of another type, replace CollectionJoin with the collection of the proper type (ListJoin, SetJoin, MapJoin).
Use this inside the specification
cq.orderBy(cb.desc(cb.count(orders)));
Also send PageRequest(1, 10, Sort.unsorted()). This is how I did it.
If you are passing the Sort value as unsorted and then override criteria query with your own logic of sorting on your joined entity