Массовое удаление 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

РЕДАКТИРОВАТЬ -> РЕШЕНО С ИСПОЛЬЗОВАНИЕМ @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) ИЛИ (ID1 = someOtherId1 И ID2 = someOtherId2) ИЛИ...)

1 ответ

Решение

Сгенерированный SQL неверен. Невозможно связать имена столбцов. Это связано с тем, что JPA не поддерживает несколько столбцов для оператора in. Более подробную информацию можно найти здесь. Запрос JPA для выбора нескольких значений в предложении "IN".

Вам необходимо создать список id.id1 = x and id.id2 = y предикаты и or их вместе.

В качестве альтернативы вы можете использовать собственный запрос, как также упоминалось в приведенном выше ответе.

Другие вопросы по тегам