【问题标题】:How to determine which properties of a RESTful resource have changed before save when using Spring Data REST repositories?使用 Spring Data REST 存储库时,如何确定 RESTful 资源的哪些属性在保存之前已更改?
【发布时间】:2026-01-23 14:20:05
【问题描述】:

如果我有 Spring Data REST 发布的以下资源...

{ "status": "idle" }

我如何对更改属性 status 的值的 PATCH 或 PUT 做出反应?想法是根据属性更改触发一些服务器进程。

理想情况下,这将在保存之前发生,并且可以将资源的新版本与之前保留的版本进行比较。

【问题讨论】:

    标签: spring spring-data spring-data-rest


    【解决方案1】:

    您通常会使用 @RepositoryEventHandler 来连接您的事件逻辑 - 请参阅 documentation for details

    我不知道直接获取更改的属性的函数。但是,如果您使用 HandleBeforeSave 处理程序,您可以加载持久实体(旧状态)并将其与新状态进行比较 -

        @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
            }
           }
        }
    

    请注意,您需要将 newPerson 与当前的 EntityManager 分离。否则我们会在调用 findOne 时获得缓存的 person 对象 - 我们无法将更新版本与当前数据库状态进行比较。

    使用 Eclipselink 时的替代方案

    如果您使用的是 eclipselink,您还可以以更有效的方式找出已应用于您的实体的更改,从而避免重新加载 - 请参阅 here for details

            UnitOfWorkChangeSet changes = entityManager.unwrap(UnitOfWork.class).getCurrentChanges();
            ObjectChangeSet objectChanges = changes.getObjectChangeSetForClone(newPerson);
            List<String> changedAttributeNames = objectChanges.getChangedAttributeNames();
            if (objectChanges.hasChangeFor("name")) {
                ChangeRecord changeRecordForName = objectChanges.getChangesForAttributeNamed("name");
                String oldValue = changeRecordForName.getOldValue();
    
            }
    

    【讨论】:

    • 这不起作用。在您的示例中,newPerson 和 currentPerson 最终成为 Person 的同一个实例。我无法获取数据库中存在的“currentPerson”。就好像 Spring Data Rest 已经将 newPerson 附加到 JPA 会话,所以后面的查询会获取新值。
    • 如果我将 EntityManager 注入到带有 @PersistenceContext 注释的 PersonEventHandler 中,并在 currentPerson 查询之前执行 entityManager.detach(newPerson),这将按预期工作。如果您更新代码以反映这一点,我会接受您的回答。
    • 感谢@GabrielBauman 的提示——你是绝对正确的——我们的查找器不会进入数据库,而是返回已经在 EntityManager 中注册的人员对象——以便能够与我们需要的当前状态进行比较之前分离对象。我相应地更新了我的答案。
    最近更新 更多