Where to raise persistence-dependent domain events - service, repository, or UI?

前端 未结 6 1913
暖寄归人
暖寄归人 2021-01-31 09:03

My ASP.NET MVC3 / NHibernate application has a requirement to fire off and handle a variety of events related to my domain objects. For example, an Order object mig

6条回答
  •  南旧
    南旧 (楼主)
    2021-01-31 09:35

    The solution turned out to be based on implementing these extension methods on the NHibernate session object.

    I was probably a little unclear with the wording of the question. The whole reason for the architectural issue was the fact that NHibernate objects are always in the same state unless you manually un-proxy them and go through all sorts of machinations. That was something I didn't want to have to do to determine what properties had been changed and therefore what events to fire.

    Firing these events in the property setters wouldn't work because the events should only fire after changes have been persisted, to avoid firing events on an operation that might ultimately fail.

    So what I did was add a few methods to my repository base:

    public bool IsDirtyEntity(T entity)
    {
        // Use the extension method...
        return SessionFactory.GetCurrentSession().IsDirtyEntity(entity);
    }
    
    public bool IsDirtyEntityProperty(T entity, string propertyName)
    {
        // Use the extension method...
        return SessionFactory.GetCurrentSession().IsDirtyProperty(entity, propertyName);
    }
    

    Then, in my service's Save method, I can do something like this (remember I'm using NServiceBus here, but if you were using Udi Dahan's domain events static class it would work similarly):

    var pendingEvents = new List();
    if (_repository.IsDirtyEntityProperty(order, "Status"))
        pendingEvents.Add(new OrderStatusChanged()); // In reality I'd set the properties of this event message object
    
    _repository.Save(order);
    _unitOfWork.Commit();
    
    // If we get here then the save operation succeeded
    foreach (var message in pendingEvents)
        Bus.Send(message);
    

    Because in some cases the Id of the entity might not be set until it's saved (I'm using Identity integer columns), I might have to run through after committing the transaction to retrieve the Id to populate properties in my event objects. Since this is existing data I can't easily switch to a hilo type of client-assigned Id.

提交回复
热议问题