如何告诉 Springdata 存储库的删除方法在实体不存在时不抛出异常?

问题描述 投票:0回答:10

我正在使用 SpringData 的存储库。如果我尝试通过不存在或从未存在过的 ID 删除实体,则会引发异常。由于我不想在删除实体之前检查该实体是否存在,因此最好它会默默地失败。这会让事情变得更容易,因为可观察的行为是相同的 - 调用后实体不再存在。不管它被删除了还是根本不存在,我不在乎。

有没有办法修改

delete(EntityId)
的默认行为,以便在实体不存在时不会抛出异常?

SpringData的delete文档说,如果实体不存在,它将抛出异常。

java spring spring-data
10个回答
38
投票

更新答案(否决后)

我原来的答案(如下)实际上是错误的:我对这个问题的理解也受到官方 JavaDoc 中缺少对

EmptyResultDataAccessException
的引用的影响(正如 Adrian Baker 在他的评论中所报道的)。

因此,山城 Rion 提出的解决方案可能是解决此问题的更好方法

if (repository.existsById(entityId)) {
    repository.deleteById(entityId);
}

或这个(没有

if
,但可能表现更差):

repository.findById(entityId)
    .map(repository::delete)

原(错误)答案

JavaDocs 表示,如果提供的参数(id、实体、

IllegalArgumentException
)为 null,则将抛出
Iterable<T>
,如果实体不存在,则不会抛出

如果您需要避免

IllegalArgumentException

,您可以实现一个自定义删除方法来检查 
id != null
:

public void customDelete(ID id) { if(id != null){ this.delete(id); } }

如果您不知道如何添加

“Spring Data 存储库的自定义实现”,请查看此文档部分


19
投票
需要更少代码的可行解决方案是在存储库界面中添加覆盖

deleteById

 方法:

@Modifying @Query("DELETE FROM <entity> WHERE ID = ?1") public void deleteById(<IdType> id);`
如果更适合您,您还可以选择本机查询:

@Modifying @Query(nativeQuery=true, value="DELETE FROM MY_TABLE WHERE ID = ?1") public void deleteById(IdPrimitiveType id);`
    

12
投票
在您的存储库中,您应定义返回类型的方法

Integer

Integer deleteMyEntityById(Long id);
如果要删除的实体不存在,则如果该实体已被删除,您的方法将返回 0 或 1。


7
投票
非常简单的解决方案:将

All

 添加到方法名称中。

使用

void deleteAllById(ID id)

 代替 
delete(ID) or deleteById(ID)

这个方法应该是你自己定义的,它不是来自spring内置的

CRUDRepository

这个方案是可行的,但是是否符合spring data规范,看评论自行判断。


4
投票
使用

JpaRepository

 您可以轻松删除实体(如果存在)。在此示例中 
PostsRepository
 扩展了 
JpaRepository
:

if (postsRepository.existsById(postId)) { postsRepository.deleteById(postId); }
    

1
投票
使用

repository.deleteAllByIdInBatch(ids);


它的工作方式与

相同

repository.deleteAllById(ids);


但在不引发异常的情况下,数据库中不存在

id

 


0
投票
重写方法:

@Transactional @Override public void delete(ID id) { T entity = findOne(id); if (entity == null) { //do something instead of throwing exception ex: //syso entity does not exist ; return; } em.remove(em.merge(entity)); }
    

0
投票
我使用@SQLDelete注释来覆盖默认的Hibernate DELETE方法并抑制异常抛出:

@javax.persistence.Entity @Table(name = "mytable") @Proxy(lazy = false) @SQLDelete( sql = "DELETE FROM mytable " + "WHERE my_id = ?" ) public class MyTable { @javax.persistence.Column(name = "my_id", nullable = false) @Id private Long id; ... }

然后 hibernate 会自动替换 '?'在准备好的语句中,具有 MyTable 对象的实际 id,该对象映射到表的 SQL 字段“my_id”

在这种情况下,如果表中的记录不存在,则不会抛出异常,只会默默删除 0 行,就像普通 SQL DELETE 查询一样


0
投票
如果找不到实体,我使用以下方法抛出有意义的异常。

if (postsRepository.existsById(postId)) { throw new EntityNotFoundExceptionById("Invlaid Id was provided"); } postsRepository.deleteById(postId);

EntityNotFoundExceptionById 类

@ResponseStatus(HttpStatus.NOT_FOUND) public class EntityNotFoundExceptionById extends RuntimeException { public EntityNotFoundExceptionById(String message) { super(message); } }
    

-1
投票
如果您只需使用单个 ID 进行删除,您可以这样做。

if(repsoitory.existsById(id)){ repository.deleteById(id) }
如果你有要删除的 ids 列表,你可以使用 java 8 

List<Long> ids=new ArrayList<>(); ids.stream().filter(id->repository.existsById(id)) .forEach(id->repository.deleteById(id));
    
© www.soinside.com 2019 - 2024. All rights reserved.