问题
slightly related to this question: Should I pass a repository to a domain object method that needs to fire an event after the methods actions have occurred and been persisted?
In this case the system needs to send emails of after the domain object's status is changed. Whilst unlikely, it could happen that the status change would not be persisted in which case the email should not be sent.
I could use a domain service to do the work, but all the logic of status changing belongs and is contained in the domain object so my services would end up looking like
StatusService(Irepo repo) {
void ChangeStatus(domainObject myObject, status newStatus) {
try {
myObject.ChangeStatus(newStatus);
repo.Save(myObject);
raiseEvent(new StausChangeEmailEvent(myObject))
} catch { .. dont send email }
}
Which id rather not do for several reason (one of which is there are now 2 ways of changing status only one of which sends the emails)
Id like to wrap it up in the Domain Method itself but this also doesn't feel right because I'm making the domain object responsible for its own persistence. (although I think I prefer it over the domain service way)
class DomainObject() : IAggRoot {
...
public ChangeStatus(irepo repo, status newStatus) {
..logic logic
this.Status = newStatus;
repo.Save(this);
raiseEvent(new StausChangeEmailEvent(myObject))
}
}
There's a bit of complications about the business logic, but really I'm interested how to fire events ONLY after the Domain Objects are persisted.
Edit: It is not so important if the email fails to send, it is important that an email is not sent if the status does not 'take' as senior people in the organisation people may receive invalid instructions in their mailbox..
回答1:
It would be nicer to have consistent transactional behavior. You could commit events in the same transaction (queue or db), and dispatch from there. Anyways, if this is not what you're looking for, you could also have your aggregate record the event instead of having it raise it directly. This allows you to first commit your database transaction, and then to dispatch the event.
public interface IRecordingAggRoot {
IEnumerable<IEvent> RecordEvents();
}
_repository.Save(aggregate);
_tx.Commit();
_dispatcher.Dispatch(aggregate.RecordedEvents());
来源:https://stackoverflow.com/questions/22084699/should-i-pass-a-repository-to-a-domain-method-that-fires-an-event