2017-09-27 270 views
0

考慮下列實體:JPA批量刪除多列主鍵

@Entity(name = "Object") 
@Table(name = "OBJECT_TABLE") 
public class ObjectEntity { 
    @EmbeddedId 
    private ObjectEntityPk id; 

    @Column(name = "SOME_ATTIBUTE") 
    private String someAttribute; 

    ... Getters/Setters 
} 

而下面的主鍵對象:

@Embeddable 
public class ObjectEntityPk { 
    @Column(name = "id1") 
    private String id1; 

    @Column(name = "id2) 
    private Long id2; 

    ... Getters/Setters 
} 

我有50 ObjectEntity刪除,我想避免循環並執行50個刪除請求。所以我寫了下面的代碼在吾道產生像刪除查詢DELETE FROM OBJECT_TABLE WHERE(ID1,ID2)IN((someId1,someId2),(someOtherId1,someOtherId2),...)

public void deleteObjects(final List<ObjectEntity> objects) { 
    CriteriaBuilder criteriaBuilder = this.entityManager.getCriteriaBuilder(); 
    CriteriaDelete<ObjectEntity> deleteCriteria = criteriaBuilder.createCriteriaDelete(ObjectEntity.class); 
    Root<ObjectEntity> rootObject= deleteCriteria.from(ObjectEntity.class); 

    Expression<ObjectEntityPk> expression = rootObject.get("id"); 
    Predicate predicate = expression.in(objects.stream().map(ObjectEntity::getId).collect(Collectors.toList())); 
    deleteCriteria.where(predicate); 
    this.entityManager.createQuery(deleteCriteria).executeUpdate(); 
} 

除了我生成的查詢有問題。表單是正確的,但它不能正確綁定列名稱。看到我得到的查詢。

DELETE FROM OBJECT_TABLE WHERE ((?, ?) IN ((?, ?), (?, ?), (?, ?), (?, ?), ...)) 
bind => [null, null, 0d287cacc63ff01b5222bf0bb2b2c794, 8105793672, 222a1399065f41b10814d88690c32bcf, 8105793874, 0b0c2f8e73475759872eb97a96f942a3, 8105794177, ...] 

我不明白爲什麼我的列名沒有綁定。我錯過了Entity或Pk的內容嗎?

提前致謝。

PS:生成的查詢Oracle數據庫上執行

EDIT - >解決USING @Guenther SOLUTION

問題是通過構建具有多個謂詞相同的請求來解決。

public void deleteObjects(final List<ObjectsEntity> objects) { 
    CriteriaDelete<ObjectEntity> deleteCriteria = this.entityManager.getCriteriaBuilder() 
        .createCriteriaDelete(ObjectEntity.class); 

    Root<ObjectEntity> rootObject = deleteCriteria.from(ObjectEntity.class); 

    List<Predicate> predicates = objects.stream().map(n -> generateAndPredicate(n, rootObject)) 
        .collect(Collectors.toList()); 

    Predicate predicate = this.entityManager.getCriteriaBuilder().or(predicates.toArray(new Predicate[predicates.size()])); 

    deleteCriteria.where(predicate); 

    this.entityManager.createQuery(deleteCriteria).executeUpdate(); 
} 

private Predicate generateAndPredicate(final ObjectEntity object, 
    final Root<ObjectEntity> rootObject) { 
    Predicate id1Equal = this.entityManager.getCriteriaBuilder().equal(rootObject.get("id").get("id1"), 
        object.getId().getId1()); 
    Predicate id2Equal = this.entityManager.getCriteriaBuilder().equal(rootObject.get("id").get("id2"), 
        object.getId().getId2()); 
    return this.entityManager.getCriteriaBuilder().and(id1Equal, id2Equal); 
} 

最後的請求看起來像DELETE FROM OBJECT_TABLE WHERE((ID1 = someId1和ID2 = someId2)OR(ID1 = someOtherId1和ID2 = someOtherId2),或)

回答

0

生成的SQL是錯的。無法綁定列名稱。這是由於以下事實:JPA不支持在聲明中使用多個列。更多細節可以在這裏找到JPA query for select which multiple values in the "IN" clause

你需要創建一個id.id1 = x and id.id2 = y謂詞列表和or他們在一起。

作爲替代方案,您可以使用原生查詢,也可以在上面引用的答案中提到。

+0

如果我正確理解你的答案。我應該建立一個請求,如** DELETE FROM OBJECT_TABLE WHERE ID1 IN(?,?,?,...)和ID2 IN(?,?,?,...)**,這是不同的請求。 –

+0

你說得對,那是不一樣的。我的錯。我會編輯答案。您需要爲每個值對添加'和'。 – Guenther