如何在@HandleBeforeSave事件中获取旧实体值以确定属性是否已更改?

Mar*_*ijk 22 java hibernate spring-data-rest

我正试图在一个@HandleBeforeSave事件中得到旧实体.

@Component
@RepositoryEventHandler(Customer.class)
public class CustomerEventHandler {

    private CustomerRepository customerRepository;

    @Autowired
    public CustomerEventHandler(CustomerRepository customerRepository) {
        this.customerRepository = customerRepository;
    }

    @HandleBeforeSave
    public void handleBeforeSave(Customer customer) {
        System.out.println("handleBeforeSave :: customer.id = " + customer.getId());
        System.out.println("handleBeforeSave :: new customer.name = " + customer.getName());

        Customer old = customerRepository.findOne(customer.getId());
        System.out.println("handleBeforeSave :: new customer.name = " + customer.getName());
        System.out.println("handleBeforeSave :: old customer.name = " + old.getName());
    }
}
Run Code Online (Sandbox Code Playgroud)

如果我尝试使用该findOne方法获取旧实体,但这将返回新事件.可能是因为当前会话中的Hibernate/Repository缓存.

有没有办法获得旧实体?

我需要这个来确定给定的属性是否被更改.如果属性是更改,我需要执行一些操作.

Gab*_*man 13

如果使用Hibernate,您只需从会话中分离新版本并加载旧版本:

@RepositoryEventHandler 
@Component
public class PersonEventHandler {

  @PersistenceContext
  private EntityManager entityManager;

  @HandleBeforeSave
  public void handlePersonSave(Person newPerson) {
      entityManager.detach(newPerson);
      Person currentPerson = personRepository.findOne(newPerson.getId());
      if (!newPerson.getName().equals(currentPerson.getName)) {
          //react on name change
      }
   }
}
Run Code Online (Sandbox Code Playgroud)

  • 这对我没有用。有关更多说明,请参见https://jira.spring.io/browse/DATAREST-373?focusedCommentId=127082&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-127082。 (2认同)

Ged*_*bel 8

感谢Marcel Overdijk创建票证 - > https://jira.spring.io/browse/DATAREST-373

我看到了这个问题的其他解决方法,并且想要提供我的解决方法,因为我认为实现起来非常简单.

首先,在您的域模型中设置一个瞬态标志(例如Account):

@JsonIgnore
@Transient
private boolean passwordReset;

@JsonIgnore
public boolean isPasswordReset() {
    return passwordReset;
}

@JsonProperty
public void setPasswordReset(boolean passwordReset) {
    this.passwordReset = passwordReset;
}
Run Code Online (Sandbox Code Playgroud)

其次,检查EventHandler中的标志:

@Component
@RepositoryEventHandler
public class AccountRepositoryEventHandler {

    @Resource
    private PasswordEncoder passwordEncoder;

    @HandleBeforeSave
    public void onResetPassword(Account account) {
        if (account.isPasswordReset()) {
            account.setPassword(encodePassword(account.getPassword()));
        }
    }

    private String encodePassword(String plainPassword) {
        return passwordEncoder.encode(plainPassword);
    }

}
Run Code Online (Sandbox Code Playgroud)

注意:对于此解决方案,您需要发送另外一个resetPassword = true参数!

对我来说,我使用以下请求有效负载向我的资源端点发送HTTP PATCH:

{
    "passwordReset": true,
    "password": "someNewSecurePassword"
}
Run Code Online (Sandbox Code Playgroud)


Maa*_*els 5

您目前在休眠状态下使用spring-data抽象。如果查找返回新值,则表明spring-data已将对象附加到休眠会话。

我认为您有三种选择:

  1. 在刷新当前季节之前,通过单独的会话/事务获取对象。这很尴尬,并且需要非常精细的配置。
  2. 在spring附加新对象之前获取以前的版本。这是完全可行的。您可以在将对象传递到存储库之前在服务层中进行操作。save当另一个感染具有已知的相同类型和ID时,您就不能将对象设为休眠会话。在这种情况下使用mergeevict
  3. 作为描述使用较低级别的Hibernate拦截器在这里。如您所见,onFlushDirty具有两个值作为参数。不过请注意,休眠状态通常不会查询您的先前状态,而只是保存一个已持久的实体。取而代之的是,在数据库中发出一个简单的更新(不选择)。您可以通过在实体上配置select-before-update来强制选择。


归档时间:

查看次数:

9465 次

最近记录:

7 年,3 月 前