我有一个带有嵌入式 id 的实体,其中包含一个 id 和 version 字段。
@Entity
@Table(name = "MyEntity")
public class MyEntity {
@EmbeddedId
private MyEntityEmbeddedId compositeId;
@Column
private DateTime begin;
@Column
private DateTime end;
}
@Embeddable
public class MyEntityEmbeddedId {
@Column(name = "ID", nullable = false, updatable = false)
private Long id;
@Column(name = "VERSION", nullable = false, updatable = false)
private Long version;
public MyEntityEmbeddedId () {}
}
我需要使用一些标准查询数据库作为实体的过滤器。例如,我将请求一个日期和一个 ID 列表。
List<MyEntity> listEntities = getMyEntities(List<Long> ids, DateTime date);
我成功创建了一个查询,该查询检索其 id 在 ids 列表中的所有实体,并且提供的日期在 MyEntity 的“开始”和“结束”日期属性之间。
但是由于这个实体有一个复合 id,所以有许多 MyEntity 具有相同的“id”,可能对应于请求参数。如果有许多具有相同的“id”,我想添加另一个过滤器来检索具有最高“版本”号的 MyEntity。
以下是数据库中可能存在的示例:
+------+-----------+--------------------+
| id | version | began | end |
+------+-----------+--------------------+
| 1 | 1 | ... | ... |
| 1 | 2 | ... | ... |
| 1 | 3 | ... | ... |
| 2 | 1 | ... | ... |
| 2 | 2 | ... | ... |
+------+-----------+--------------------+
如果之前所有的数据库记录都对应过滤参数,我只需要得到这一条,因为它们是对应id的版本号最高的:
+------+-----------+--------------------+
| id | version | began | end |
+------+-----------+--------------------+
| 1 | 3 | ... | ... |
| 2 | 2 | ... | ... |
+------+-----------+--------------------+
目前,我执行请求,但我在服务内的方法中过滤版本,但如果版本已在数据库请求中过滤,我更喜欢它。我不需要检索过滤版本后将被丢弃的记录。
我正在寻找一种使用 JPA Criteria-API 进行自我加入的方法。
在以下链接中,似乎接受的答案将解决我的问题,因为我想知道如何在 JPA Criteria-API 中翻译建议的 SQL。
select yt1.*
from yourtable yt1
left outer join yourtable yt2
on (yt1.id = yt2.id and yt1.rev < yt2.rev)
where yt2.id is null;
我的问题是当我尝试创建连接时。您需要提供来自第一个实体的属性,该属性链接到连接中的第二个实体。由于我想进行自联接,因此我的实体内部没有指向自身的属性。
Join<MyEntity, MyEntity> selfJoin = root.join(MyEntity_.???);
如您所见,我使用的是 MyEntity 的静态元模型。有没有办法使用 JPA Criteria-API 进行自我加入?
或者,也许有另一种方法来构建我的请求,而不是像另一个 stackoverflow 问题中所建议的那样使用自左连接。
我正在使用 Spring Data JPA Specification 来构建我的 Predicate 查询。然后使用 findAll(Specification)。我已经有另外两种规范方法来为 withIds() 和 withDate() 生成谓词。这让我可以使用用户提供的“未确定数量”的参数创建查询。
public static Specification<MyEntity> withIdAndDate(final List<Long> ids,
final DateTime date) {
return new Specification<MyEntity>() {
@Override
public Predicate toPredicate(Root<MyEntity> root, CriteriaQuery<?> query,
CriteriaBuilder cb){
Join<MyEntity, MyEntity> selfJoin = root.join();
Predicate pIds = withIds(ids).toPredicate(root, query, cb);
Predicate pDate = withDate(date).toPredicate(root, query, cb);
return cb.and(pIds, pDate);
}
};
}
非常感谢您的帮助和建议!