我需要一些似乎不是很具体的东西,但是无论如何我都无法提出好的复杂解决方案。

假设我有一个非常简单的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值更改为false。同样,如果任何实体发生更改(其defaultType更改为true),则应应用相同的规则。

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

那么,什么是最佳解决方案?

最佳答案

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

@Entity
@EntityListeners(com.acme.AlertMonitor.class) // set callback method in another class
public class Account {
   Long accountId;
   Integer balance;
   boolean preferred;

   @Id
   public Long getAccountId() { ... }
   ...
   public Integer getBalance() { ... }
    ...
   @Transient
   public boolean isPreferred() { ... }
   ...

   public void deposit(Integer amount) { ... }
   public Integer withdraw(Integer amount) throws NSFException {... }

   @PreUpdate // callback method in some class
   protected void validateCreate() {
     if (getBalance() < MIN_REQUIRED_BALANCE)
        throw new AccountException("Insufficient balance to open an
account");
   }

  @PostUpdate  // callback method in some class
  protected void adjustPreferredStatus() {
      preferred =
      (getBalance() >= AccountManager.getPreferredStatusLevel());
   }
}

// callback method in another class
public class AlertMonitor {
   @PreUpdate  // callback method in another class
   public void updateAccountAlert(Account acct) {
      Alerts.sendMarketingInfo(acct.getAccountId(), acct.getBalance());
   }
}

更新:关于您的问题,如果我不了解您想要的内容,此代码可以为您提供帮助:
@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和@PrePresist,并且每次覆盖所有Type对象时都不会存储任何变量(与第一个示例相比,它对性能而言不是很好,但更可靠):
@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);
           }
       }
    }
 }

07-24 21:15