Hibernate / JPA:只有一个条目可以具有特定的字段值

时间:2015-12-08 21:57:40

标签: java hibernate jpa java-ee jdbc

我需要一些看似不那么具体的东西,但无论如何我都无法提出漂亮而复杂的解决方案。

说我有非常简单的hibernate / jpa实体:

@Entity(name="entity")
public class Type {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Long id;

    @Column(unique = true, nullable = false)
    private String name;

    @Column(unique = false, nullable = false)
    private boolean defaultType;
}

我需要的是以某种方式注释 defaultType 字段,因此只有(并且确切地说)一个持久化实体将此值设为true。当新实体持续使用此 defaultType 为true时,必须更改旧实体( defaultType = true)实体及其 defaultType 值改为假。此外,如果任何实体被更改(其 defaultType 已更改为true),则应适用相同的规则。

据我所知,这可以在业务逻辑内部实现(例如在DAO层),使用DB触发器或使用hibernates拦截器或事件(如果有其他方式,请告诉我)。我尝试使用DAO解决方案,但它是一种糟糕的解决方案,因为它可以被绕过,对于这种简单的操作来说真的很笨拙。数据库触发器无法添加hibernate / jpa注释(如果我没有记错),我不知道如何使用hibernate拦截器/事件来实现此功能。

那么,这个问题的最佳解决方案是什么?

1 个答案:

答案 0 :(得分:1)

您需要在JPA中使用Callback方法,例如PreUpdatePostUpdate,例如:

@Entity(name="entity")
@EntityListeners(com.yourpackage.TypeListner.class)
public class Type {

    ...
@Column(unique = false, nullable = false)
private boolean defaultType;
}

public class TypeListner {

pivate static Type objectWithTrue = null;

public void init() { // call this method when application is started 
    List<Type> results = entityManager
                  .createQuery("from Type", Type.class)
                  .getResultList();
    for(Type type: results) {
         if(type.getDefaultType()) {
             objectWithTrue = type;      
         }  
    }
}

private void changeDefaultType(Type changed) {
    if(changed.getDefaultType()) {
       if(changed != objectWithTrue && objectWithTrue != null) {        
         objectWithTrue.setDefaultType(false);
       }
       objectWithTrue = changed;
   }
}

@PostPresist  
public void newType(Type changed) {
   changeDefaultType(changed);
}

@PostUpdate
public void updateType(Type changed) {
   changeDefaultType(changed);
}

@PreRemove
public void removeType(Type changed) {
if(changed.getDefaultType() && objectWithTrue == changed) {
      objectWithTrue = null;
    }
}

更新:关于您的问题,如果我找不到您想要的内容,此代码可能会对您有所帮助:

@PreUpdate 
void updateType(Type changed) {
    if(changed.getDefaultType()
        List<Type> results = entityManager
                  .createQuery("from Type", Type.class)
                  .getResultList();
       for(Type type: results) {
           if(changed != type && type.getDefaultType()) {
             type.setDefaultType(false);    
           }  
       }
    }
 }

您可以使用listner @PreUpdate和@PrePresist,并且每次覆盖所有Type对象而不存储任何变量(对于性能而言,这不是第一个示例,但更可靠):

class Lion extends Animal{

    public Lion() {
        super(new String[]{"steak", "celery"});
    }

    //...

}