在条件查询规范中合并不同类型的规范 [英] Merge specifications of different types in Criteria Query Specifications
问题描述
我有一个 Activity
实体,该实体与 Event
实体及其相应的元模型处于 @ManyToOne
关系中- Activity_
和 Event _
是由JPA模型生成器生成的.
I'm having an Activity
entity which is in @ManyToOne
relationship with Event
entity and their corresponding metamodels - Activity_
and Event_
were generated by JPA model generator.
我已经创建了专门的类 ActivitySpecifications
和 EventSpecifications
.这些类仅包含返回 Specification
的静态方法.例如:
I've created specialized classes ActivitySpecifications
and EventSpecifications
. Those classes contain only static methods whose return Specification
. For example:
public interface EventSpecifications {
static Specification<Event> newerThan(LocalDateTime date) {
return (root, cq, cb) -> cb.gt(Event_.date, date);
}
...
}
因此,当我要构建匹配多个规范的查询时,可以在 JpaSpecificationExecutor< Event>
存储库上使用 findAll
执行以下语句.
so when I want to build query matching multiple specifications, I can execute following statement using findAll
on JpaSpecificationExecutor<Event>
repository.
EventSpecifications.newerThan(date).and(EventSpecifications.somethingElse())
和 ActivitySpecifications
示例:
static Specification<Activity> forActivityStatus(int status) { ... }
如何使用 ActivitySpecifications
中的 EventSpecifications
?我的意思是喜欢不同类型的合并规范.很抱歉,但是我什至不知道如何正确地提出问题,但是有一个简单的例子:
How do I use EventSpecifications
from ActivitySpecifications
? I mean like merge specifications of different type. I'm sorry, but I don't even know how to ask it properly, but theres simple example:
我要选择状态为:status
且 activity.event.date
大于:date
I want to select all activities with status = :status
and where activity.event.date
is greater than :date
static Specification<Activity> forStatusAndNewerThan(int status, LocalDateTime date) {
return forActivityStatus(status)
.and((root, cq, cb) -> root.get(Activity_.event) ....
// use EventSpecifications.newerThan(date) somehow up there
}
这样可能吗?
我想到的最接近的东西是使用以下内容:
The closest thing that comes to my mind is using the following:
return forActivityStatus(status)
.and((root, cq, cb) -> cb.isTrue(EventSpecifications.newerThan(date).toPredicate(???, cq, cb));
其中 ???
需要 Root< Event>
,但是我只能使用 root.get获得
. Path< Event>
(Activity_.event)
where ???
requires Root<Event>
, but I can only get Path<Event>
using root.get(Activity_.event)
.
推荐答案
在规范的基本形式中,仅当规范引用相同的根时,规范才可以组合.
In its basic form, specifications are designed to be composable only if they refer to the same root.
但是,引入自己的接口应该很容易,该接口可以容易地转换为 Specification
,并且允许引用任意实体的规范组成.
However, it shouldn't be too difficult to introduce your own interface which is easily convertible to Specification
and which allows for specifications refering to arbitrary entities to be composed.
首先,添加以下界面:
@FunctionalInterface
public interface PathSpecification<T> {
default Specification<T> atRoot() {
return this::toPredicate;
}
default <S> Specification<S> atPath(final SetAttribute<S, T> pathAttribute) {
// you'll need a couple more methods like this one for all flavors of attribute types in order to make it fully workable
return (root, query, cb) -> {
return toPredicate(root.join(pathAttribute), query, cb);
};
}
@Nullable
Predicate toPredicate(Path<T> path, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder);
}
然后,您按如下所示重写规格:
You then rewrite the specifications as follows:
public class ActivitySpecifications {
public static PathSpecification<Activity> forActivityStatus(ActivityStatus status) {
return (path, query, cb) -> cb.equal(path.get(Activity_.status), cb.literal(status));
}
}
public class EventSpecifications {
public static PathSpecification<Event> newerThan(LocalDateTime date) {
return (path, cq, cb) -> cb.greaterThanOrEqualTo(path.get(Event_.createdDate), date);
}
}
完成此操作后,您应该可以通过以下方式编写规范:
Once you've done that, you should be able to compose specifications in the following manner:
activityRepository.findAll(
forActivityStatus(ActivityStatus.IN_PROGRESS).atRoot()
.and(newerThan(LocalDateTime.of(2019, Month.AUGUST, 1, 0, 0)).atPath(Activity_.events))
)
上述解决方案的另一个优点是,将指定 WHERE
条件与指定路径分离开,因此,如果 Activity
和 Event 之间存在多个关联,代码>,您可以为所有代码重用
Event
规范.
The above solution has the additional advantage in that specifying WHERE
criteria is decoupled from specifying paths, so if you have multiple associations between Activity
and Event
, you can reuse Event
specifications for all of them.
这篇关于在条件查询规范中合并不同类型的规范的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!