JPA Criteria API 过滤器子实体

2024-01-14

代码示例:

    @Entity
    public class Event {

    @Id
    @GeneratedValue
    private Long id;
    private String name;
    @OneToMany(mappedBy="event")
    private List<Actions> actions;

    }


    @Entity
    public class Action {

    @Id
    @GeneratedValue
    private Long id;
    private String name;
    private Date date;
    @ManyToOne
    @JoinColumn(name = "event_id")
    private Event event;

    }

    public class EventSpecification {

    public static Specification<Event> findByCriteria(EventSearchCriteria criteria) {

        return (root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();

            criteria.getDate().ifPresent(date -> {
                Join<Event, Action> join = root.join(Event_.actions);
                predicates.add(criteriaBuilder.equal(join.get(Action_.date), criteria.getDate().get()));
            });

            return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
        };
    }
    }
...

eventRepository.findAll(EventSpecification.findByCriteria(searchCriteria))

在我的数据库中,我有下一个:

Event Table
id, name
1, 'event_1'
2, 'event_2'

Action Table
id, name, date, event_id
1, 'action_event_1_1', '01-01-2018', 1
2, 'action_event_1_2', '01-01-2018', 1
3, 'action_event_1_3', '01-02-2018', 1

4, 'action_event_2_1', '01-03-2018', 2

使用带有 data='01-01-2018' 的规范代码,结果我得到了相同事件对象的列表,列表的大小是连接对象的计数,满足子句 Action.date = criteria.date:

[{id=1, name=event_1, actions=[all 3 actions]},
{id=1, name=event_1, actions=[all 3 actions]}]

我需要得到下一个结果:

{id=1, name=event_1, actions=[only two actions with date '01-01-2018']}

我尝试添加

criteriaQuery.groupBy(root.get(Event.id));

它修复了结果列表的大小 -

{id=1, name=event_1, actions=[all 3 actions]}

但我仍然得到事件 1 的所有 3 个操作。

问题是:

是否可以仅获取包含具有所需日期的操作的事件,以便每个事件仅包含具有请求日期的操作的列表?


我找到了下一个解决方案:

public static Specification<Event> findByCriteria(EventSearchCriteriacriteria) {

        return (root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();

            criteria.getDate().ifPresent(date -> {
                criteriaQuery.distinct(true);
                Join<Event, Action> join = (Join<Event, Action>)root.fetch(Event_.actions);
                predicates.add(criteriaBuilder.equal(join.get(Action_.date), criteria.getDate().get()));
            });

            return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
        };
    }

大概Join<Event, Action> join = (Join<Event, Action>)root.fetch(Event_.actions);不是最好的解决方案,因为我的 IDE 会警告我有关转换的问题,但这是我找到的唯一可行的解​​决方案。

顺便说一句,如果不使用 Criteria API,它也能完美工作:

@EntityGraph(value = "Event.actions", type = EntityGraph.EntityGraphType.LOAD)
@Query("select distinct e from Event e join e.actions a where a.date = (:date)")
List<Event> findAllWithActionsByDate(@Param("date") Date date);

但避免 Criteria API 不适合我的情况。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

JPA Criteria API 过滤器子实体 的相关文章

随机推荐