Use-Case:
I implemented a soft-delete semantic on my Book entity.
@Entity
public class Book {
@Column
private Boolean deleted;
}
A Book is soft deleted by setting this flag. For sure all queries should respect this deleted-flag ... at least in most use-cases.
My Solution:
I did not want to refactor all the queries because this is a very big application and the risk is too high that DEVs overlooked (now and in future). I wanted to implement a solution that sits on a central place and needs less maintenance (in the JPA framework) - adapting all queries automatically.
My current (working) solution is based on @Customizer(ExcludeDeletedContent.class) annotation:
@Entity
@Customizer(ExcludeDeletedContent.class)
public class Book {
@Column
private Boolean deleted;
}
The Customizer looks this way
public class ExcludeDeletedContent implements DescriptorCustomizer {
public void customize(ClassDescriptor descriptor) throws Exception {
ExpressionBuilder eb =
new ExpressionBuilder(descriptor.getJavaClass());
hideBlockedExpression = eb.get("deleted").notEqual(true);
descriptor.getQueryManager().setAdditionalJoinExpression(
hideBlockedExpression);
}
}
Also Page (entity) has a similar DescriptorCustomizer (Book -> Page have 1:n relationship).
My Problem:
This approach is working BUT I do not know how to switch this behavior off for some use-cases (I want to see also the deleted books) ... in best case by setting a property within EntityManager (as possible in @AdditionalCriteria).
What I already tried:
- Option 1: within ExcludeDeletedContent.customize I tried to identify my use-case (via a ThreadLocal containing some relevant informations) but this ended in a weird result ... hiding of deleted Books did not work anymore. It seemed that event a minimal code like boolean bla = counter % 2 == 0 (counter was a static variable inside ExcludeDeletedContent) made my ExcludeDeletedContent stop working. It seems that the Customizer behave somehow weird ... I was not able to debug into it.
- Option 2: I found this example using a placeholder that is set into the EntityManager and resolved by EclipseLink (similar to @AdditionalCriteria - where it was working in my code): http:__java-persistence.blogspot.de/2010/08/eclipselink-filters-how-to.html - this would fit for my use-case - BUT: I cannot find a SessionPropertyValue implementation in EclipseLink
P.S.: My first approach was based on @AdditionalCriteria but I had NPE-exception (org.eclipse.persistence.internal.expressions.ObjectExpression.getOwnedTables(ObjectExpression.java:585 - EclipseLink 2.6.1)) when I tried to express JPQLs that navigated from Page to Book via @JoinColumn property book like this:
@AdditionalCriteria("this.book.deleted <> 1)")
@Entity
public class Page {
@JoinColumn
private Book book;
}
For me it was not working ...