无法通过 MediatR 实体框架调度多个域事件

问题描述 投票:0回答:0

我的一个实体中有一个状态,如果该状态被取消或完成,那么我想调度一个通过 MediatR 发送的事件。如果状态是付款成功,我想发送一封电子邮件,然后继续取消/完成的活动。

实体看起来像这样:

public Order : BaseEntity
{
   ....

   private OrderStatus _status = OrderStatus.InProgress;

   public OrderStatus Status
    {
        get => _status;
        set
        {
            if (SentAt != null)
            {
                // Already done the workflow, no longer need to do them.
                _status = value;
                return;
            }

            if (value is OrderStatus.Cancelled or OrderStatus.Completed)
            {
                AddDomainEvent(new SendOrderStatusUpdate(this));
            }

            if (value == OrderStatus.PaymentSuccessful)
            {
                AddDomainEvent(new SendInvoice(this));
            }

            _status = value;
        }
    }
}

但是,当我运行这个时。如果我将订单状态设置为

OrderStatus.PaymentSuccessful
,它会运行整个事件,最后我将状态设置为
OrderStatus.Completed
,它不会运行与该状态相关的域事件。

我的

BaseEntity
课程与推荐的方法相对相同:

public class BaseEntity
{
    /// <summary>
    /// The identifier for the entity.
    /// </summary>
    [Key]
    public int Id { get; set; }
    
    /// <summary>
    /// The domain events.
    /// </summary>
    private readonly List<BaseEvent> _domainEvents = new();
    
    [NotMapped]
    public IReadOnlyCollection<BaseEvent> DomainEvents => _domainEvents.AsReadOnly();
    
    public void AddDomainEvent(BaseEvent domainEvent)
    {
        _domainEvents.Add(domainEvent);
    }
    
    public void RemoveDomainEvent(BaseEvent domainEvent)
    {
        _domainEvents.Remove(domainEvent);
    }
    
    public void ClearDomainEvents()
    {
        _domainEvents.Clear();
    }
}

然后,我扩展 MediatR 以与 Hangfire 一起使用,以便对事件进行排队并在后台执行它们,这也是推荐的方法。

public static class MediatorExtensions
{
    public static async Task DispatchDomainEvents(this IMediator mediator, DbContext context)
    {
        var entities = context.ChangeTracker
            .Entries<BaseEntity>()
            .Where(e => e.Entity.DomainEvents.Any())
            .Select(e => e.Entity);

        var domainEvents = entities.SelectMany(e => e.DomainEvents).ToList();

        entities.ToList().ForEach(e => e.ClearDomainEvents());

        foreach (var domainEvent in domainEvents)
        {
            var client = new BackgroundJobClient();

            client.Enqueue<MediatorBridge>(bridge => bridge.Publish(domainEvent));
        }
    }
}

我期待辅助域事件会触发,但是,它似乎并没有进入那里。

我最初认为

ClearDomainEvents
方法可能会变得混乱并在触发之前清除域事件。我已确认情况并非如此,事件似乎正在“调度”,但 MediatR
INotificationHandler<SendOrderStatusUpdate>
未进入。

将订单状态设置为

OrderStatus.Completed
会立即正确触发该工作流程,因此我觉得这与正在运行的订单及其处理方式有关。

更新:

我已经开始工作了,但并不完全。

我已将调度更新为以下内容:

public static async Task DispatchDomainEvents(this IMediator mediator, DbContext context)
{
    var entities = GetEntitiesWithPendingEvents(context);

    while (entities.Any())
    {
        foreach (var entity in entities)
        foreach (var domainEvent in entity.DomainEvents.ToList())
        {
            var client = new BackgroundJobClient();
            client.Enqueue<MediatorBridge>(bridge => bridge.Publish(domainEvent));
            entity.RemoveDomainEvent(domainEvent);
        }

        entities = GetEntitiesWithPendingEvents(context);
    }
}

private static List<BaseEntity> GetEntitiesWithPendingEvents(DbContext context)
{
    return context.ChangeTracker
        .Entries<BaseEntity>()
        .Where(e => e.Entity.DomainEvents.Any())
        .Select(e => e.Entity)
        .ToList();
}

当更新在另一个事件处理程序中触发时,它会获取更新。然而,这在立即调用它时有效,即:

_mediator.Publish(domainEvent)
,但在我当前的设置中不起作用,我试图通过 Hangfire 传递它。好像没收到。

c# .net entity-framework mediatr
© www.soinside.com 2019 - 2024. All rights reserved.