简体   繁体   中英

Spring Data domain events go missing (?)

I am having trouble publishing events from an aggregate-root in a Spring Boot application. What I basically want is to publish an "Update" event every time some information about a person is changed. The code for this is pretty straightforward:

@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();
  }
}

I am managing Person instances through a manager:

@Service
@Transactional
class PersistentPersonManager implements PersonManager {

 // other methods are omitted

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

}

However when I call the manager ( manager.save(person.updateInformation(...)) the events seem to go "missing": upon calling the save() method all events are still present but when Spring invokes getModificationEvents() the collection is empty. The events seem to have vanished somewhere in between (with only Spring-code being executed).

As this is pretty basic, I must be missing something essential but got stuck in a rut.

So how do I get back on track here?

I assume you are using JPA here.

For JPA the save operation actually does a merge on the JPA EnityManager .

For a detached entity merge loads/finds the entity with the same id from the database or the current session and copies all the (changed) fields over. This does ignore transient fields like the events.

You are dealing with detached entities because you are creating a new entity every time you call updateInformation .

So here is what is happening:

  1. You load an entity ( e1 ) from the database. It does not have any events registered.

  2. By calling updateInformation you create a new detached entity ( e2 ). You also register events with e2 .

  3. When calling save JPA finds the matching e1 and copies all changes from e2 into it, except the events. So e1 still has no events registered.

  4. Events get triggered, but there aren't any because only e1 is used.

In order to fix this: Do not create new instances of the entity in updateInformation .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM