Reputation: 1115
I must be doing something wrong here.
I have a very simple Axon application that has two simple functions: create a person & change the name of the person.
So I have Person Entity:
@Entity
@Data
@NoArgsConstructor
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
}
And my PersonAggregate:
@Aggregate
@Data
@NoArgsConstructor
public class PersonAggregate {
@AggregateIdentifier
private UUID id;
private String name;
@CommandHandler
public PersonAggregate(CreatePersonCommand command) {
apply(new PersonCreatedEvent(
command.getId(),
command.getName()
));
}
@EventSourcingHandler
public void on(PersonCreatedEvent event) {
this.id = event.getId();
this.name = event.getName();
}
@CommandHandler
public void handle(ChangeNameCommand command) {
apply(
new NameChangedEvent(
command.getId(),
command.getName()
)
);
}
@EventSourcingHandler
public void on(NameChangedEvent event) {
this.name = event.getName();
}
}
And this is my ChangeNameCommand:
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ChangeNameCommand {
@TargetAggregateIdentifier
private UUID id;
private String name;
}
And this is my NameChangedEvent:
@Value
public class NameChangedEvent {
private final UUID id;
private final String name;
}
And Repository:
@Repository
public interface PersonCommandRepository extends JpaRepository<Person, Long> {
}
The Problem is that I am not sure how to structure my Event Handler
@EventHandler
public void changeName(NameChangedEvent event) {
Optional<Person> opt = null;//this.personCommandRepository.findById(event.getId());
if (opt.isPresent()) {
Person person = opt.get();
person.setName(event.getName());
this.personCommandRepository.save(person); //Does'nt this defeat the purpose of Event Sourcing? A single point of truth?
}
And also, in my controller, I have quite I big problem, in the comment:
@RequestMapping(value = "/rename", method = RequestMethod.POST)
public ResponseEntity<?> changeName(@RequestParam("id") Long id, @RequestParam("name")String name){
//1. Which Id do we pass in here? Aggregate or Entity?
//this.commandGateway.send(new ChangeNameCommand(id,name));
return new ResponseEntity<String>("Renamed", HttpStatus.OK);
}
}
Upvotes: 0
Views: 906
Reputation: 7275
I feel you are still mixing the idea of the Command Model and the Query Model with one another.
The command model, which typically is the aggregate (or several), only handles requests of intent to change some state. These requests of intent, i.e. command message, are thus the sole operations targeted towards your aggregate/command model. Vice versa, if you have the requirement to change something on a Person, that means you dispatch a command marking that intent towards the PersonAggregate
.
The query model on the other hand is solely tasked with answering the questions targeted towards your application. If there is somehow a need to know the state of a Person, that means you dispatch a query towards a component capable of returning the Person
entity you have shared.
Going back to "the problems" you described:
On AxonIQ's webpage there is an Architectural Concepts section describing all the main principles. There's also one about CQRS which might help. Might help to read up on these; pretty sure a lot of these will solve a lot of the question you have. :-)
Hope this helps!
Upvotes: 1