4

I have found the need to limit the size of a child collection by a property in the child class.

I have the following after following this guide:

@FilterDef(name="dateFilter", parameters=@ParamDef( name="fromDate", type="date" ) )
public class SystemNode implements Serializable {

    @Getter
    @Setter
    @Builder.Default
    // "startTime" is a property in HealthHistory
    @Filter(name = "dateFilter", condition = "startTime >= :fromDate")
    @OneToMany(mappedBy = "system", targetEntity = HealthHistory.class, fetch = FetchType.LAZY)
    private Set<HealthHistory> healthHistory = new HashSet<HealthHistory>();

    public void addHealthHistory(HealthHistory health) {
        this.healthHistory.add(health);
        health.setSystem(this);
    }
}

However, I don't really understand how to toggle this filter when using Spring Data JPA. I am fetching my parent entity like this:

public SystemNode getSystem(UUID uuid) {
    return systemRepository.findByUuid(uuid)
        .orElseThrow(() -> new EntityNotFoundException("Could not find system with id " + uuid));
}

And this method in turn calls the Spring supported repository interface:

public interface SystemRepository extends CrudRepository<SystemNode, UUID> {

    Optional<SystemNode> findByUuid(UUID uuid);

}

How can I make this filter play nicely together with Spring? I would like to activate it programatically when I need it, not globally. There are scenarios where it would be viable to disregard the filter.

I am using Spring Boot 1.3.5.RELEASE, I cannot update this at the moment.

4
  • 1
    I think you could enable it for 1 call and immediatly disable it again. An example can be found here Commented Apr 10, 2018 at 11:31
  • @XtremeBaumer I have found that source, but that forces me to circumvent the Spring repository entirely and use HQL to define my own query. I want to avoid that if possible, but I don't know if it is. Commented Apr 10, 2018 at 11:38
  • 2
    No it doesn't. Before calling the repository method get hold of the EntityManager. Use EntityManager.unwrap(Session.class) to get the underlying Hibernate Session. Call enableFilter, call the repository method, call disableFilter. Commented Apr 10, 2018 at 11:43
  • @M.Deinum thanks, I will give it a try! Commented Apr 10, 2018 at 12:21

1 Answer 1

6

Update and solution

I tried the following as suggested to me in the comments above.

@Autowired
private EntityManager entityManager;

public SystemNode getSystemWithHistoryFrom(UUID uuid) {
    Session session = entityManager.unwrap(Session.class);

    Filter filter = session.enableFilter("dateFilter");
    filter.setParameter("fromDate", new DateTime().minusHours(4).toDate());

    SystemNode systemNode = systemRepository.findByUuid(uuid)
            .orElseThrow(() -> new EntityNotFoundException("Could not find system with id " + uuid));

    session.disableFilter("dateFilter");

    return systemNode;
}

I also had the wrong type in the FilterDef annotation:

@FilterDef(name="dateFilter", parameters=@ParamDef( name="fromDate", type="timestamp" ) )

I changed from date to timestamp.

This returns the correct number of objects, verified against the database.

Thank you!

Sign up to request clarification or add additional context in comments.

3 Comments

And what when in parent entity I have OneToMany and then I'd like to add condition on third nested entity like A.fieldB.fieldC.fieldD.id = x... How to achieve this with Filter in this case?
I don't understand why you need a hibernate filter here. You could use any filtering method you want here. The only way a hibernate filter could be useful is if you can enable it from several endpoints at once (using an aspect, for example ?).
@AdrienH this answer is over four years old, a lot has probably happened since then.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.