繁体   English   中英

“不正确的 PK”:删除使用 @IdClass 注释的实体的 CrudRepository 操作

[英]"incorrect PK" : delete operation on CrudRepository for entity annotated with @IdClass

语境

当我的服务调用repository.delete(myEntity) ,我收到以下错误:

105 | 您为此查找操作提供了不正确的 PK 类的实例。 预期类:com.foo.PrimaryKey 类,接收到的类:java.lang.String 类

存储库接口extends CrudRepository<MyEntity, PrimaryKey>

我在@Entity类上使用@IdClass(PrimaryKey.class)并用@Id标记相关的单个字段。 PrimaryKey有一个字段,它是一个String 我们这样做是为了保持我们的代码库一致,以便每个@Entity始终将其主键声明为复合键。

我自己的分析(可能有误)

出于某种原因,JPA 在内部调用em.find(MyEntity.class, primaryKeyString)而不是从该 String 构建PrimaryKey实例并使用它,因此出现错误。

当我尝试调用repository.deleteById(correspondingPrimaryKeyInstance)时会发生同样的错误。

框架代码

这来自org.springframework.data.jpa.repository.support.SimpleJpaRepository ,我在事情失败的地方添加了一条评论:

    @Override
    @Transactional
    @SuppressWarnings("unchecked")
    public void delete(T entity) {

        Assert.notNull(entity, "Entity must not be null!");

        if (entityInformation.isNew(entity)) {
            return;
        }

        Class<?> type = ProxyUtils.getUserClass(entity);

        T existing = (T) em.find(type, entityInformation.getId(entity)); // IT FAILS HERE... `entityInformation.getId(entity)` returns a String instead of the expected `PrimaryKey`

        // if the entity to be deleted doesn't exist, delete is a NOOP
        if (existing == null) {
            return;
        }

        em.remove(em.contains(entity) ? entity : em.merge(entity));
    }

代码

  • 存储库:
public interface MyEntityCRUDRepository extends CrudRepository<MyEntity, PrimaryKey> { }
public interface MyEntityCustomRepository { /* some custom operations */ }

@Repository
public interface MyEntityRepository extends MyEntityCRUDRepository, MyEntityCustomRepository { }
  • 服务:
@Service
@Transactional(rollbackFor = Exception.class)
@RequiredArgsConstructor
public class MyEntityService {
    private final MyEntityRepository repository;

    public void destroy(final PrimaryKey pk) {
//        repository.deleteById(pk); // also returns the error
        MyEntity myEntity = repository.findById(pk)
                .orElseThrow(() -> new IllegalArgumentException(DOES_NOT_EXIST));
        repository.delete(myEntity); // returns the error
    }
}
  • JPA实体:
@Entity
@Table(name = "myentity")
@JsonIgnoreProperties(ignoreUnknown = true)
@Data
@NoArgsConstructor
@AllArgsConstructor
@IdClass(PrimaryKey.class)
public class MyEntity {

    @Id
    @Column(name = "the_id", updatable = false)
    private String theId;

    // other fields which aren't part of the primary key
}
  • 主键类:
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class PrimaryKey implements Serializable {
    private String theId;
}

临时修复:当您只有一个作为 ID 的属性时,不要使用@IdClass

@Entity
@Table(name = "myentity")
@JsonIgnoreProperties(ignoreUnknown = true)
@Data
@NoArgsConstructor
@AllArgsConstructor
//@IdClass(PrimaryKey.class)
public class TemporaryReservation {

    @Id
    @Column(name = "the_id", updatable = false)
    private String theId;

    // other fields which aren't part of the primary key
}
public interface MyEntityCRUDRepository extends CrudRepository<MyEntity, String> { }

更改后,在其余代码中进行适当调整。

原来这是Spring Data一个错误。 请参阅相关(现已解决)问题: https : //github.com/spring-projects/spring-data-jpa/issues/2330

其中一位维护者说:

另一种解决方法是让您的实体实现Persistable

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM