删除未保存的对象不会调用异常
Delete not saved object doesnt invoke exception
我正在为我的 Dao Spring
应用程序编写测试。我发现当我删除未保存的项目时,没有像我预期的那样调用异常,我不知道为什么。
型号:
@Entity
public class Ingredient {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String condition;
private int quantity;
public Ingredient() {
}
}
Dao
实现:
@Override
public void delete(Object o) throws DaoException {
try {
Session session = mSessionFactory.openSession();
session.beginTransaction();
session.delete(o);
session.getTransaction().commit();
session.close();
} catch (Exception ex) {
throw new DaoException(ex, String.format("Problem deleting %s object (delete method).", o));
}
}
还有我的测试,期待 DaoException
:
@Test
public void testDeleteNotSavedThrowsDaoException() throws Exception {
Ingredient ingredient = new Ingredient("Not saved ingredient","", 1);
ingredientDao.delete(ingredient);
}
Hibernate 的 Session#delete(Object) Javadoc 指出:
Remove a persistent instance from the datastore. The argument may be an instance associated with the receiving Session or a transient instance with an identifier associated with existing persistent state.
所以传递一个临时实体不是错误(就像你所做的那样)。此外,Session#delete
方法未声明任何异常,因此未定义当您传入具有数据库中不存在的 ID 的实体时会发生什么。如您所见 - 什么都没有发生 - 您请求实体不存在于数据库中,它不在那里开始,所以没有理由抛出异常(至少根据 Hibernate)。
将此与基本的 SQL DELETE FROM X WHERE ID = Y
进行比较 - 这不会检查是否存在具有 ID=Y
的记录,无论哪种方式都会成功(更新 0 或 1 行)。
UPDATE 意识到传入的瞬态实体具有 null
ID。
我已经深入研究了 Hibernate 5.2.2 Session
的源代码,似乎如果传入的实体没有 ID,甚至不会对该实体的 table.
见DefaultDeleteEventListener#onDelete(DeleteEvent, Set)
:
if (ForeignKeys.isTransient( persister.getEntityName(), entity, null, source ) ) {
// yes, your entity is transient according to ForeignKeys.isTransient
deleteTransientEntity( source, entity, event.isCascadeDeleteEnabled(), persister, transientEntities );
return;
}
现在
protected void deleteTransientEntity(
EventSource session,
Object entity,
boolean cascadeDeleteEnabled,
EntityPersister persister,
Set transientEntities) {
LOG.handlingTransientEntity(); // Only log it
if ( transientEntities.contains( entity ) ) {
LOG.trace( "Already handled transient entity; skipping" );
return;
}
transientEntities.add( entity );
// Cascade deletion to related entities
cascadeBeforeDelete( session, persister, entity, null, transientEntities );
cascadeAfterDelete( session, persister, entity, transientEntities );
}
这只会在日志中打印 "HHH000114: Handling transient entity in delete processing"
并且不会对实体执行任何操作(但是,如果有相关实体,它会将删除级联到相关实体 - 不是你的情况)。
再说一次 - 可以传入一个没有 ID 的临时实体 - 它不会 运行 数据库上的 DELETE
。
这是一个答案,亚当,没有例外,因为我新的、未保存的项目的 ID 为空。当我将 id 设置为在数据库中不存在的值时,抛出异常。
我正在为我的 Dao Spring
应用程序编写测试。我发现当我删除未保存的项目时,没有像我预期的那样调用异常,我不知道为什么。
型号:
@Entity
public class Ingredient {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String condition;
private int quantity;
public Ingredient() {
}
}
Dao
实现:
@Override
public void delete(Object o) throws DaoException {
try {
Session session = mSessionFactory.openSession();
session.beginTransaction();
session.delete(o);
session.getTransaction().commit();
session.close();
} catch (Exception ex) {
throw new DaoException(ex, String.format("Problem deleting %s object (delete method).", o));
}
}
还有我的测试,期待 DaoException
:
@Test
public void testDeleteNotSavedThrowsDaoException() throws Exception {
Ingredient ingredient = new Ingredient("Not saved ingredient","", 1);
ingredientDao.delete(ingredient);
}
Hibernate 的 Session#delete(Object) Javadoc 指出:
Remove a persistent instance from the datastore. The argument may be an instance associated with the receiving Session or a transient instance with an identifier associated with existing persistent state.
所以传递一个临时实体不是错误(就像你所做的那样)。此外,Session#delete
方法未声明任何异常,因此未定义当您传入具有数据库中不存在的 ID 的实体时会发生什么。如您所见 - 什么都没有发生 - 您请求实体不存在于数据库中,它不在那里开始,所以没有理由抛出异常(至少根据 Hibernate)。
将此与基本的 SQL DELETE FROM X WHERE ID = Y
进行比较 - 这不会检查是否存在具有 ID=Y
的记录,无论哪种方式都会成功(更新 0 或 1 行)。
UPDATE 意识到传入的瞬态实体具有 null
ID。
我已经深入研究了 Hibernate 5.2.2 Session
的源代码,似乎如果传入的实体没有 ID,甚至不会对该实体的 table.
见DefaultDeleteEventListener#onDelete(DeleteEvent, Set)
:
if (ForeignKeys.isTransient( persister.getEntityName(), entity, null, source ) ) {
// yes, your entity is transient according to ForeignKeys.isTransient
deleteTransientEntity( source, entity, event.isCascadeDeleteEnabled(), persister, transientEntities );
return;
}
现在
protected void deleteTransientEntity(
EventSource session,
Object entity,
boolean cascadeDeleteEnabled,
EntityPersister persister,
Set transientEntities) {
LOG.handlingTransientEntity(); // Only log it
if ( transientEntities.contains( entity ) ) {
LOG.trace( "Already handled transient entity; skipping" );
return;
}
transientEntities.add( entity );
// Cascade deletion to related entities
cascadeBeforeDelete( session, persister, entity, null, transientEntities );
cascadeAfterDelete( session, persister, entity, transientEntities );
}
这只会在日志中打印 "HHH000114: Handling transient entity in delete processing"
并且不会对实体执行任何操作(但是,如果有相关实体,它会将删除级联到相关实体 - 不是你的情况)。
再说一次 - 可以传入一个没有 ID 的临时实体 - 它不会 运行 数据库上的 DELETE
。
这是一个答案,亚当,没有例外,因为我新的、未保存的项目的 ID 为空。当我将 id 设置为在数据库中不存在的值时,抛出异常。