✅ Short Answer
When you write a JPQL or native SQL query without explicitly including deleted = false
, you risk retrieving soft-deleted rows, because without a @Where
filter, your query doesn’t exclude them by default.
🔎 Detailed Explanation
🔹 What happens with @Where
?
If you add @Where(clause="deleted=false")
to your entity, Hibernate automatically appends AND deleted=false
to all:
✅ Entity-level queries like em.find()
.
✅ HQL or Criteria queries on the entity itself (e.g., FROM User
).
🔹 But what if you skip it in JPQL?
For example:
List<User> users = em.createQuery("SELECT u FROM User u", User.class).getResultList();
✅ If @Where
is present → Hibernate adds deleted=false
automatically.
❌ But if:
- You don’t use @Where, or
- Your query doesn’t target the entity directly, e.g., you query a DTO:
List<String> names = em.createQuery(
"SELECT u.name FROM User u", String.class).getResultList();
→ Hibernate doesn’t inject the deleted filter automatically, so you must manually add it:
List<String> names = em.createQuery(
"SELECT u.name FROM User u WHERE u.deleted=false", String.class).getResultList();
🔹 Native queries
If you use em.createNativeQuery(...)
, Hibernate has no idea about your entity’s mapping → @Where
is ignored completely → you must always add deleted=false
manually.
Example:
// Missing filter: may return soft-deleted rows!
List<Object[]> result = em.createNativeQuery("SELECT * FROM user").getResultList();
🔹 Why does this matter?
✅ Without filtering out deleted=true
rows, your app could:
- Show deleted/inactive data to users → violating business rules.
- Process old, logically removed records.
📌 Key Takeaways
✅ @Where(deleted=false)
automatically filters entity-based queries, but
❌ JPQL or native SQL without explicit deleted=false
can include soft-deleted rows.
✅ Always double-check manual queries to ensure you exclude logically deleted data!