Spring Data域事件丢失(?)

时间:2017-12-30 16:34:39

标签: java spring jpa events spring-data

我在Spring Boot应用程序中从聚合根发布事件时遇到问题。我基本上想要的是每次有关某人的某些信息发生变化时发布“更新”事件。 这个代码非常简单:

@Entity
public class Person {
  @Transient
  private final Collection<AbstractPersonRelatedEvent> events = new ArrayList<>();

  Person(Person other) {
    // copy other fields
    other.events.foreach(events::add);
  }

  // other stuff

  public Person updateInformation(...) {
    Person updated = new Person(this);

    // setting new data on the updated person

    if (!hasUpdateEventRegistered()) {
      updated.registerEvent(PersonDataUpdatedEvent.forPerson(updated));
    }
    return updated;
  }

  void registerEvent(AbstractPersonRelatedEvent event) {
    events.add(event);
  }

  @DomainEvents
  Collection<AbstractPersonRelatedEvent> getModificationEvents() {
    return Collections.unmodifiableCollection(events);
  }

  @AfterDomainEventPublication
  void clearEvents() {
    events.clear();
  }
}

我通过经理管理Person个实例:

@Service
@Transactional
class PersistentPersonManager implements PersonManager {

 // other methods are omitted

  @Override
  public Person save(Person person) {
    return personRepository.save(person);
  }

}

然而,当我打电话给经理时(manager.save(person.updateInformation(...))事件似乎“失踪”: 在调用save()方法时,所有事件仍然存在,但是当Spring调用getModificationEvents()时,该集合为空。事件似乎在两者之间消失了(只执行了Spring代码)。

由于这是非常基本的,我必须遗漏一些必要的东西,但却陷入了困境。

那我该如何回到正轨呢?

1 个答案:

答案 0 :(得分:2)

我假设你在这里使用JPA。

对于JPA,save操作实际上在JPA merge上执行了EnityManager

对于分离的实体merge从数据库或当前会话加载/查找具有相同id的实体,并复制所有(已更改的)字段。这确实会忽略事件等瞬态字段。

您正在处理已分离的实体,因为每次调用updateInformation时都要创建一个新实体。

所以这就是发生的事情:

  1. 您从数据库加载实体( e1 )。它没有注册任何事件。

  2. 通过调用updateInformation,您可以创建一个新的分离实体( e2 )。您还可以使用 e2 注册活动。

  3. 调用save时,JPA会找到匹配的 e1 并将所有更改从 e2 复制到其中,但事件除外。所以 e1 仍然没有注册事件。

  4. 事件被触发,但没有任何因为只使用 e1

  5. 为了解决此问题:请勿在{{1​​}}中创建实体的新实例。