在Hibernate中保护实体免于级联删除

简单的问题:有没有人有任何想法如何保护某些实体在运行时hibernate 通过CascadeType.ALL删除(可能会抛出运行时exception)?

说,我们有一些实体:

 @Entity @Table(name = "FOO_ENTITY") public class FooEntity { ... } 

我想保护它免受意外的错误映射,例如:

 @Entity @Table(name = "SOME_OTHER_FOO_ENTITY") public class SomeOtherFooEntity { ... @ManyToOne(cascade = CascadeType.ALL) @JoinColumn(name = "FOO_ENTITY_ID") private FooEntity fooEntity; } 

因此,应该可以通过session.delete(fooEntityObj)删除某个类型为FooEntity实体,但必须禁用它才能通过级联删除删除它( session.delete(someOtherFooEntityObj) )。

注意 :对于那些读我的问题不专心或认为我不明白我在问什么的人:

1)我无法删除 CascadeType.ALL 。 问题是:谁编程避免和保护这个?

2)unit testing不是方法,我正在寻找运行时解决方案。

其中一种方法是以编程方式检查Hibernate映射元数据,并检查是否有任何删除操作( ALLREMOVEorphanRemoval )从任何其他实体级联到受保护实体; 就像是:

 String protectedEntityName = FooEntity.class.getName(); SessionFactoryImpl sessionFactory = (SessionFactoryImpl) session.getSessionFactory(); for (EntityPersister entityPersister : sessionFactory.getEntityPersisters().values()) { for (int i = 0; i < entityPersister.getPropertyTypes().length; i++) { Type type = entityPersister.getPropertyTypes()[i]; EntityType entityType = null; if (type.isCollectionType()) { CollectionType collectionType = (CollectionType) type; Type elementType = sessionFactory.getCollectionPersister(collectionType.getRole()).getElementType(); if (elementType.isEntityType()) { entityType = (EntityType) elementType; } } else if (type.isEntityType()) { entityType = (EntityType) type; } if (entityType != null && entityType.getName().equals(protectedEntityName)) { if (entityPersister.getPropertyCascadeStyles()[i].doCascade(CascadingAction.DELETE)) { // Exception can be thrown from here. System.out.println("Found! Class: " + entityPersister.getEntityName() + "; property: " + entityPersister.getPropertyNames()[i]); } } } } 

可以在服务器启动或集成测试中执行此validation。

这种方法的优点是您不必修改Hibernate的已定义行为; 它只是提醒您忘记不要将删除级联到FooEntity

关于测试,是的,我知道OP明确表示测试不是这个用例的可接受的解决方案(我个人同意它)。 但是这些类型的自动测试可能是有用的,因为你写它们并忘记它们; 您无需在添加新映射或修改现有映射时更新测试(这会破坏测试的目的,因为您可能会忘记或监督为每个可能的用例采用测试)。

对于初学者,我认为你确实理解了你的要求,你刚刚确定了一个特定的解决方案,许多人,包括我自己,都在质疑。 这不是不专心……它试图解决你的实际问题。

如果你真的想要停止注释上的CascadeType.ALL值来获得其记录的效果,而不是validationCascadeType.ALL是否在不应该使用的地方(并通过unit testingvalidation这些期望),那么扩展DefaultDeleteEventListener和覆盖deleteEntity方法以始终将false传递给isCascadeDeleteEnabled标志的超级实现。

如果您想要一个具有某种标准的预期行为的解决方案,那么定义应该在模式级别执行级联删除的关系,并建立最佳实践以仅使用您在代码中关注的CascadeType 。 也许这是PERSIST和MERGE,也许您正在使用会话工厂的保存和更新function,因此您需要使用特定于Hibernate的@CascadeType注释。

如果您不想将更改级联到与真正更改的对象相关联的对象,那么您是否只能从@ManyToOne注释中删除cascade属性?

捕获任何编程错误的最可靠方法是编写unit testing。

如果您练习测试驱动开发,您将最大限度地减少“忘记”这样做的机会。