【问题标题】:Delete from association table that have primary composite key从具有主复合键的关联表中删除
【发布时间】:2020-01-29 10:09:34
【问题描述】:

当我想从具有复合键和额外列的关联表中删除时遇到问题。

关联表由一个实体表示,该实体具有两个 Object,CollaboratorCompetence,具有关系 @ManyToOne。另一方面,我有关系 @OneToManyCollaboratorCompetence Entity 有一个 复合键(collaborator_id,competition_id)。

当我执行此 查询 以删除 collaborators_competences 表上的一行时,它可以工作。

查询 1

DELETE FROM collaborators_competences WHERE (collaborator_id, competence_id)
                                                IN (SELECT collaborator_id, competence_id FROM collaborators_competences
                                                    JOIN collaborators c on collaborators_competences.collaborator_id = c.id
                                                JOIN competences c2 on collaborators_competences.competence_id = c2.id
                                                WHERE c.id = (SELECT collaborators.id FROM collaborators WHERE login = :collabLogin) AND c2.id = :competenceId)

查询 2(简化)

DELETE FROM  collaborators_competences cc WHERE cc.collaborator_id = (SELECT collaborators.id FROM collaborators WHERE collaborators.login = :collabLogin)AND cc.competence_id = :competenceId

现在,当我使用存储库执行相同的 查询 时,我收到一个错误 “无法提取结果集”

存储库

public interface CollaboratorCompetenceRepository extends JpaRepository<CollaboratorCompetence, CollaboratorCompetenceId> {
    Optional<CollaboratorCompetence> findById(CollaboratorCompetenceId id);

//    @Query(value = "DELETE FROM CollaboratorCompetence " +
//        "WHERE CollaboratorCompetence.collaborator IN (SELECT Collaborator FROM Collaborator WHERE Collaborator.login = :collabLogin)" +
//        "AND CollaboratorCompetence.competence IN (SELECT COmpetence FROM Competence WHERE Competence.id = :competenceId)")
//    @Query(value = "DELETE FROM  collaborators_competences WHERE collaborator_id = 1128 AND competence_id = 2551", nativeQuery = true)
    @Query(value = "DELETE FROM collaborators_competences WHERE (collaborator_id, competence_id)\n" +
        "                                                IN (SELECT collaborator_id, competence_id FROM collaborators_competences\n" +
        "                                                    JOIN collaborators c on collaborators_competences.collaborator_id = c.id\n" +
        "                                                JOIN competences c2 on collaborators_competences.competence_id = c2.id\n" +
        "                                                WHERE c.id = (SELECT collaborators.id FROM collaborators WHERE login = :collabLogin) AND c2.id = :competenceId)", nativeQuery = true)
    void deleteByCollaboratorLoginAndCompetenceId(@Param("collabLogin") String login, @Param("competenceId") Long id);

    void deleteCollaboratorCompetenceById(CollaboratorCompetenceId id);
}

即使是spring数据,hibernate也只执行select查询,不执行delete查询。

协作者能力实体

@Entity
@Table(name = "collaborators_competences")
public class CollaboratorCompetence {

    @EmbeddedId
    private CollaboratorCompetenceId id;

    @ManyToOne
    @MapsId("collaboratorId")
    private Collaborator collaborator;

    @ManyToOne
    @MapsId("competenceId")
    private Competence competence;

    @Column(name = "note")
    private Integer note;

    public CollaboratorCompetence() {
    }

    public CollaboratorCompetence(Collaborator collaborator, Competence competence, Integer note) {
        this.id = new CollaboratorCompetenceId(collaborator.getId(), competence.getId());
        this.collaborator = collaborator;
        this.competence = competence;
        this.note = note;
    }

CollaboratorCompetenceId(可嵌入类)

@Embeddable
public class CollaboratorCompetenceId implements Serializable {

    @JoinColumn(name = "competence_id", table = "collaborators_competences")
    private Long competenceId;

    @JoinColumn(name = "collaborator_id", table = "collaborators_competences")
    private Long collaboratorId;

    public CollaboratorCompetenceId() {
    }

    public CollaboratorCompetenceId(Long competenceId, Long collaboratorId) {
        this.competenceId = competenceId;
        this.collaboratorId = collaboratorId;
    }

    public Long getCompetenceId() {
        return competenceId;
    }

    public void setCompetenceId(Long competenceId) {
        this.competenceId = competenceId;
    }

    public Long getCollaboratorId() {
        return collaboratorId;
    }

    public void setCollaboratorId(Long collaboratorId) {
        this.collaboratorId = collaboratorId;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        CollaboratorCompetenceId that = (CollaboratorCompetenceId) o;
        return Objects.equals(competenceId, that.competenceId) &&
            Objects.equals(collaboratorId, that.collaboratorId);
    }

    @Override
    public int hashCode() {
        return Objects.hash(competenceId, collaboratorId);
    }

    @Override
    public String toString() {
        return "CollaboratorCompetenceId{" +
            "competenceId=" + competenceId +
            ", collaboratorId=" + collaboratorId +
            '}';
    }
}

错误堆栈:

Caused by: org.hibernate.exception.GenericJDBCException: could not extract ResultSet
    at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:47)
    at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:111)
    at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:97)
    at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:69)
    at org.hibernate.loader.Loader.getResultSet(Loader.java:2168)
    at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1931)
    at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1893)
    at org.hibernate.loader.Loader.doQuery(Loader.java:938)
    at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:341)
    at org.hibernate.loader.Loader.doList(Loader.java:2692)
    at org.hibernate.loader.Loader.doList(Loader.java:2675)
    at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2507)
    at org.hibernate.loader.Loader.list(Loader.java:2502)
    at org.hibernate.loader.custom.CustomLoader.list(CustomLoader.java:335)
    at org.hibernate.internal.SessionImpl.listCustomQuery(SessionImpl.java:2200)
    at org.hibernate.internal.AbstractSharedSessionContract.list(AbstractSharedSessionContract.java:1016)
    at org.hibernate.query.internal.NativeQueryImpl.doList(NativeQueryImpl.java:152)
    at org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1414)
    at org.hibernate.query.internal.AbstractProducedQuery.getSingleResult(AbstractProducedQuery.java:1463)
    at org.springframework.data.jpa.repository.query.JpaQueryExecution$SingleEntityExecution.doExecute(JpaQueryExecution.java:214)
    at org.springframework.data.jpa.repository.query.JpaQueryExecution.execute(JpaQueryExecution.java:91)
    at org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:136)
    at org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:125)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:602)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:590)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
    at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:294)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)
    ... 175 common frames omitted
Caused by: org.postgresql.util.PSQLException: Aucun résultat retourné par la requête.
    at org.postgresql.jdbc.PgPreparedStatement.executeQuery(PgPreparedStatement.java:107)
    at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeQuery(ProxyPreparedStatement.java:52)
    at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeQuery(HikariProxyPreparedStatement.java)
    at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:60)
    ... 203 common frames omitted

【问题讨论】:

  • 你能翻译这行Aucun résultat retourné par la requête.吗?
  • 查询没有返回结果
  • 在下面查看我的答案

标签: java spring postgresql hibernate spring-data-jpa


【解决方案1】:

您需要在查询中添加注释@Modifying

@Modifying
@Transactional
@Query(value = "DELETE FROM collaborators_competences WHERE (collaborator_id, competence_id)\n" +
    "                                                IN (SELECT collaborator_id, competence_id FROM collaborators_competences\n" +
    "                                                    JOIN collaborators c on collaborators_competences.collaborator_id = c.id\n" +
    "                                                JOIN competences c2 on collaborators_competences.competence_id = c2.id\n" +
    "                                                WHERE c.id = (SELECT collaborators.id FROM collaborators WHERE login = :collabLogin) AND c2.id = :competenceId)", nativeQuery = true)
void deleteByCollaboratorLoginAndCompetenceId(@Param("collabLogin") String login, @Param("competenceId") Long id);




@Transactional
void deleteCollaboratorCompetenceById(CollaboratorCompetenceId id);

@Modifying的使用

正如注释所说,它用于修改查询。现在,什么是修改查询。

  • 修改查询是任何向实体写入一些数据的查询,即修改实体。这包括更新和删除查询。
  • @Modifying 应该用于 JPA 存储库中使用 @Query 注释的自定义查询

注意: 有时您可能会得到RollBackException 的异常,此时您需要使用@Transactional 注释处理逻辑。当您遇到此类异常时,只需使用 @Transactional 注释您的方法或存储库方法签名即可。

【讨论】:

  • 谢谢Mansoor,你能解释一下我什么时候应该添加它吗?效果很好。
  • 是的,非常感谢,但是当我尝试使用这种方法删除spring数据时:@Modifying void deleteCollaboratorCompetenceById(CollaboratorCompetenceId id); 它不起作用,hibernate执行唯一的选择请求你知道为什么吗?
  • 您可以尝试删除@Modifying 吗?
  • 删除/更新查询返回整数,即受影响的行数。能不能先改签。然后看看实际问题。
  • 先添加@Transactional。如果它不起作用,则可能没有与该 ID 关联的任何数据。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-13
  • 2012-05-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多