Spring data join with specifications - join data from referenced column - java

I have a table which stores the orders. The orders table has an 'One to Many' mapping to another table, which stores ordered item, orderItems. For each row of the orderItems, it refers to a row in the Product table. And I have another table which stores product image, the product image table has a foreign key which points to the product. How can I use JPA specifications to join the product image in the query result of the orders?
Something like:
Order -> [orderId, ... orderItems[],...]
OrderItem -> [orderitemId, ... product,...]
Product -> [productId, productname... ]
ProductImage -> [producdImageId, .... productId...]
I am searching on Order table.
thanks!

Related

Spring JPA: Association requirement when joining tables

We have two tables, ORDER and STATUS.
For every change in the orders in ORDER table, we enter the audit into STATUS table with lastUpdatedDateTime.
Sometimes, I just need to fetch order detail and sometimes I need latest status along with order details.
How should I design my entity and how should I join tables when needed?
Do I need to add associations to join table(using criteria builder)?
If I add associations, status data from STATUS table will be pulled even when not needed (e.g. when doing findBy on ORDER where we just need order details)?
Also when I display to the User the orders, they should look like below. Need status and lastUpdatedBy in the Order object
[
{
"OrderId": "1",
"product": "pen",
"status": "IP",
"lastUpdatedBy": "user1"
},
{
"OrderId": "1",
"product": "book",
"status": "CP",
"lastUpdatedBy": "user2"
}
]
I have tried using association and criteria builder to join tables.
Questions:
A right way to design my entites
how to join tables to fetch the top record from status table for a given order.
(P.S i need to use predicates as I have dynamic where clause requirement)
Sample SQL
Select f, o.statusCode, o.lastUpdatedBy
from FX_ORDER f left join ORDER o
ON f.ORDER_ID = o.ORDER_ID
and f.SEQUENCE= o.SEQUENCE
where o.statusCode = 'IP'
and o.lastUpdatedDateTime in (select max(s.lastUpdatedDateTime)
from ORDER s where
s.ORDER_ID = o.ORDER_ID
and s.SEQUENCE= o.SEQUENCE);
Based on the information, it seems like you have a one-to-many relationship between ORDER and STATUS tables, where an ORDER can have multiple STATUS records.
To design your entities, you can create two classes: Order and Status. The Order class will have a collection of Status objects as a member variable to represent the one-to-many relationship. The Order class will also have attributes for OrderId and product, and the Status class will have attributes for statusCode, lastUpdatedBy, and lastUpdatedDateTime. You can then use JPA annotations to map these classes to the corresponding tables in the database.
When you want to fetch order details with the latest status, you can use a query that joins the ORDER and STATUS tables and selects the top record from the STATUS table for each ORDER record.Check below example query
SELECT o.OrderId, o.product, s.statusCode, s.lastUpdatedBy
FROM ORDER o
LEFT JOIN STATUS s ON o.OrderId = s.OrderId
AND s.lastUpdatedDateTime = (
SELECT MAX(s2.lastUpdatedDateTime)
FROM STATUS s2
WHERE s2.OrderId = o.OrderId
)
This query joins the ORDER and STATUS tables on the OrderId column and uses a subquery to select the latest STATUS record for each ORDER record. The LEFT JOIN ensures that all ORDER records are included in the result, even if there are no corresponding STATUS records.
To use this query with dynamic where clause requirements, you can create a JPA CriteriaQuery object and add predicates to it based on the search criteria.Here's an example
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Order> query = cb.createQuery(Order.class);
Root<Order> orderRoot = query.from(Order.class);
Join<Order, Status> statusJoin = orderRoot.join("statuses", JoinType.LEFT);
query.multiselect(
orderRoot.get("OrderId"),
orderRoot.get("product"),
statusJoin.get("statusCode"),
statusJoin.get("lastUpdatedBy")
);
List<Predicate> predicates = new ArrayList<>();
predicates.add(cb.equal(statusJoin.get("statusCode"), "IP"));
query.where(predicates.toArray(new Predicate[0]));
query.orderBy(cb.desc(statusJoin.get("lastUpdatedDateTime")));
List<Order> result = em.createQuery(query).getResultList();

Sql Many to many query ask

product
id_product
productName
componentID
component
componentdID
nameofComponent
what i have here is a list of products that are gonna be in Combobox and on the right it's gonna be jtable in which i need when i pick a product it lists all components that are needed to make that product. How do i make sql query in selectProduct.
Also to mention 1 product can have up to 100 components. And There is atleast 50 products
Thanks
and you should avoid the direct use on componetId in product table avoid unusefulf replication of product for mantain the relation with componenent
for this
You could create a specific table for mantain the relation between products and components eg:
table product_component ( id, product_id, componentdID )
then you can select the component of a product as
select a.productName, b.nameofComponent
from product_component c
inner join product a on a.product_id = c.product_id
inner join component b on b.componentdID = c.componentdID
and for a specific product
select a.productName, b.nameofComponent
from product_component c
inner join product a on a.product_id = c.product_id
inner join component b on b.componentdID = c.componentdID
where a.product_id = your_product_id_value

MySql and java {getting related tables columns}

I have created 2 tables in MySQL [items, orderList], the foreign key id in orderlist references the primary key id in items. Now I want to take all columns{id, name, price (in Items), and quantity (in orderList)} from 2 tables in Java, how can I show id once because when I query data it shows id from both tables?
You can do with join queries, try the below query and select the fields whatever you want from two tables
SELECT items.id, items.name, items.price, orderList.quantity
FROM items INNER JOIN orderList ON items.id = orderList.id
In order to fetch the data only once, you need to mention where it should come from. You can try the following:
SELECT I.ID, I.NAME, I.PRICE, O.QUANTITY FROM ORDERLIST O, ITEMS I WHERE I.ID = O.ID
Here we have given aliases to both the tables and we have mentioned that the ID column will be picked from the ITEMS table.

How to filter child collection in JPQL query?

I've the following DB model:
Category -< ProductCategory >- Product -< Variant
(Category has many-to-many relationship with Product and Product has one-to-many relationship with Variant)
Now I need to get all Category records that have product with active variants. I'm getting these objects via the following JPQL query:
#Query("select distinct c from Category c join c.products as p join p.variants as pv where pv.active = true")
It works well - returns categories accurately - however every single Category contains all the products - not only these with active variants.
How can I filter out the products (or variants) that are inactive in a single query?
Here's a postgres script that with database struct and sample data. For given data two categories (CAT 1, CAT 2), two products (PROD 1, PROD 2) and three variants (VAR 1, VAR 2, VAR 3) should be returned.
I had exactly the same problem and it took me a while to find out how this works. The child list should be filtered when you add FETCH after your JOIN like this:
SELECT DISTINCT c FROM Category c JOIN FETCH c.products as p join p.variants as pv where pv.active = true
I have the same problem on it, and I found that the FetchType in the #OneToMany annotation is important. It need to be set as Lazy mode. If it is Eager mode, jpa will create the sql query to fetch the data from the table for your child collection and won't filter it for you.

JPA/Hibernate query construction

I am fetching records from my "record" table. "record" table has many columns tow of which are
client_id, foreign key mapping to client table.
creation_date , date of record creation
I would like to do a query on this table , but I would like to fetch only one record per client(latest creation_date record has preference).
Will following work?
select r.id,r.xx,r.yy
group by(r.client_id),r.creation_date
from record r
order by creation_date desc
I tried above and seems records fetched are not of latest creation dates.
Hope my question is clear
Just keep your query and add a WHERE condition :
SELECT r.id,r.xx,r.yy
GROUP BY(r.client_id)
FROM record r
WHERE r.creation_date = (SELECT MAX(creation_date) FROM record tmp WHERE tmp.client_id = r.client_id )
Take a look at This discussion
This should give you a good starting point in HQL.
from Record as r inner join fetch r.client
where r.creation_date > (
select max(rec.creation_date) from Record rec
where rec.client.client_id = r.client.client_id
)
This of course assumes that your Record has a reference to its parent Client called client.

Categories

Resources