1

在版本字段上过滤实体我有一个包含id和version字段的嵌入id的实体。使用JPA Criteria-API

@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); 

我成功创建该retreives所有实体,他们的ID是在IDS列表所提供的日期是myEntity所的“开始”和“结束”日期属性之间的查询。

但是由于这个实体有一个复合id,所以有许多MyEntity具有相同的“id”,可以对应请求参数。我想添加另一个过滤器来检索具有最高“版本”号码的MyEntity,如果有许多具有相同的“ID”。

这里是什么可能是数据库中的一个例子:

+------+-----------+--------------------+ 
| 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。

SQL Select only rows with Max Value on a Column

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来构建带有谓词的查询。然后使用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); 
     } 

    }; 
} 

非常感谢您的帮助和建议!

回答

0

最后,我成功地找到了一种方法来将我的MyEntity过滤为使用JPA Criteria API的最新版本,因此我将与您分享我的代码,希望它能帮助此处的某人。

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){ 

      Subquery<Long> subqueryVersion = query.subquery(Long.class); 
      Root<MyEntity> entity1 = subqueryVersion.from(MyEntity.class); 

      Expression<Long> expMaxVersion = cb.greatest(entity1 
       .get(MyEntity_.compositeId).get(MyEntityEmbeddedId_.version)); 
      Expression<Long> expIdRoot = root.get(MyEntity_.compositeId) 
       .get(MyEntityEmbeddedId_.id); 
      Expression<Long> expIdEntity1 = entity1 .get(MyEntity_.compositeId) 
       .get(MyEntityEmbeddedId_.id); 
      Expression<Long> expVersionRoot = root.get(MyEntity_.compositeId) 
       .get(MyEntityEmbeddedId_.version); 

      Predicate pId = cb.equal(expIdRoot, expIdEntity1); 
      Predicate pIds = withIds(ids).toPredicate(entity1, query, cb); 
      Predicate pDate = withDate(date).toPredicate(entity1, query, cb); 

      subqueryVersion.select(expMaxVersion); 
      subqueryVersion.where(pId, pIds, pDate); 

      Predicate pQuery = cb.equal(expVersionRoot, subqueryVersion); 

      return cb.and(pQuery); 
     } 

    }; 
} 

在以下链接中,接受的答案帮助我在JPQL中构建查询,之后我成功将其转换为JPA Criteria API。我删除了“AND NOT EXISTS”部分的查询的最后部分。 JPA Select latest instance for each item