简体   繁体   中英

how to filter a left join in jpa query

I'm having trouble with a JPA object not being returned. I've got customers and addresses, customer can have zero or more addresses. I also soft delete items. This query works, except when there's no addresses returned I don't get the customer details back (returns null ).

So I set my query like this:

select c from Customer c
left join fetch c.createUser 
left join fetch c.lastUpdateUser 
left join fetch c.addressBook a 
where c.id = 1 and c.markForDelete = false 
and (a.id is null or a.markForDelete = false)

It works fine if there's a row in addressBook . But if I delete all the addresses I'm getting no result back.

The equivalent of what I'm trying to accomplish in SQL is:

select * from customers c
left join customer_addresses ca
on c.id = ca.customer_id
and c.markForDelete = 0
and ca.markForDelete = 0;

which works and gives me a single result.

OK, using similar data here, I found the following query should do what you want:

SELECT DISTINCT c FROM Customer c
LEFT JOIN FETCH c.createUser
LEFT JOIN FETCH c.lastUpdateUser
LEFT JOIN FETCH c.addressBook a
WHERE c.id = 1 AND c.markForDelete = false
AND (SIZE(c.addressBook) = 0 OR a.markForDelete = false)

Note, I found that the DISTINCT was important, otherwise I got repeated data (Customers in your case).

Also, the Customers that are returned which have Addresses will NOT return ALL addresses for that Customer. The attached list will only have the Addresses that have markForDelete false.

I've come to the conclusion that this is impossible with JPA as it is. Even with Hibernate specific @Where annotations it's difficult at best.

The only way I found to do what I wanted which is pretty straightforward case of "soft-delete" items, was:

  1. Annotate the relationship , not the related entity, with Hibernate specific @Where(clause="markForDelete<>'1')

  2. Do NOT use left join fetch because it seems to ignore the additional criteria even when it's annotated.

  3. Instead use the standard join ,then access the property from within the transaction to trigger the subquery.

I guess using soft deletes has pretty much rendered fetch joins unusable for me... I really find JPA and Hibernate so frustrating to work with sometimes.

It's interesting that EclipseLink seems to have support for soft-deletes according to this page: https://wiki.eclipse.org/EclipseLink/Examples/JPA/SoftDelete

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM