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