在Hibernate中保护实体免受级联删除 [英] Protect entity from cascade delete in Hibernate

查看:112
本文介绍了在Hibernate中保护实体免受级联删除的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



说,我们有一些实体:

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

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

  @Entity 
@Table(name =SOME_OTHER_FOO_ENTITY)
公共类SomeOtherFooEntity {

.. 。

@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name =FOO_ENTITY_ID)
private FooEntity fooEntity;

$ / code>

因此,应该可以删除<$ c $类型的实体c> FooEntity 通过 session.delete(fooEntityObj),但它必须被禁用才能通过级联删除来删除它( session.delete(someOtherFooEntityObj))。



注意:对于那些不注意我的问题的读者,不明白我在问什么:

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

2)单元测试不是这样,我正在寻找运行时解决方案。

解决方案

ALL REMOVE orphanRemoval )级联到受保护来自任何其他实体的实体;例如:

 字符串protectedEntityName = FooEntity.class.getName(); 
SessionFactoryImpl sessionFactory =(SessionFactoryImpl)session.getSessionFactory(); (EntityPersister entityPersister:sessionFactory.getEntityPersisters()。values()){
for(int i = 0; i< entityPersister.getPropertyTypes()。length; i ++){

b $ b Type type = entityPersister.getPropertyTypes()[i];
EntityType entityType = null;
if(type.isCollectionType()){
CollectionType collectionType =(CollectionType)type;
类型elementType = sessionFactory.getCollectionPersister(collectionType.getRole())。getElementType();
if(elementType.isEntityType()){
entityType =(EntityType)elementType;
}
} else if(type.isEntityType()){
entityType =(EntityType)type; (entityType!= null&& entityType.getName()。equals(protectedEntityName)){
if(entityPersister.getPropertyCascadeStyles()[i] .doCascade(CascadingAction。
) DELETE)){
//可以从这里抛出异常。
System.out.println(Found!Class:+ entityPersister.getEntityName()+; property:+ entityPersister.getPropertyNames()[i]);
}
}
}
}

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



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



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


Simple question: does anyone have any ideas how to protect some entity from being deleted via CascadeType.ALL in hibernate in runtime (may be with throwing a runtime exception)?

Say, we have some entity:

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

And I want to protect it from accidental wrong mapping, like:

@Entity
@Table(name = "SOME_OTHER_FOO_ENTITY")
public class SomeOtherFooEntity {

    ...

    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "FOO_ENTITY_ID")
    private FooEntity fooEntity;
}

So, it should be possible to delete some entity of type FooEntity via session.delete(fooEntityObj), but it must be disabled ability to delete it via cascade removal (session.delete(someOtherFooEntityObj)).

ATTENTION: For those who read my question inattentive or think that I do not understand what am I asking:

1) I can not remove CascadeType.ALL. The question is: who programming avoid and protect from this?

2) Unit tests is not the way, I'm looking for runtime solution.

解决方案

One of the ways this can be done is to programmatically inspect Hibernate mapping meta-data and to check whether any delete operation (ALL, REMOVE, orphanRemoval) cascades to the protected entity from any other entity; something like:

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]);
            }
        }
    }
}

This validation can be performed on server startup or in an integration test.

The advantage of this approach is that you don't have to modify the defined behavior of Hibernate; it just acts as a reminder that you forgot not to cascade deletion to the FooEntity.

Regarding the tests, yes, I know that the OP explicitly said that tests are not an acceptable solution for this use case (and I personally agree with it in general). But these kinds of automatic tests may be useful because you write them and forget about them; you don't have to update the tests whenever you add a new mapping or modify an existing one (which defeats the purpose of the tests because you may forget or oversee to adopt the tests for each possible use case).

这篇关于在Hibernate中保护实体免受级联删除的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆