繁体   English   中英

为什么在 CQRS 模式中的 AddDomainEvent 之后不返回值

[英]Why Not returning value after AddDomainEvent in CQRS pattern

我在我的项目中使用 CQRS 模式和 MediatR。在 2 个部分中,它并没有像我期望的那样结束。

1:当我想用命令改变后返回一个值时,我使用(例如:usermanager)保存更改,所以创建的视图model不再返回,而是发送到事件推送路径。

基础实体:

public abstract class BaseEntity : IBaseId<string>, IEntityWithDomainEvent
{
    public string Id { get; set; }
    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();
    }
    
}
public class LoginUserCommand : IRequest<ResponseLoginViewModel>
{
    public string PhoneNumber { get; set; }
    public string VerifyCode { get; set; }
    public string ReturnUrl { get; set; }
}

public class LoginUserCommandHandler : IRequestHandler<LoginUserCommand, ResponseLoginViewModel>
{
    private readonly IIdentityService _identityService;

    public LoginUserCommandHandler(IIdentityService identityService)
    {
        _identityService = identityService;
    }
    public async Task<ResponseLoginViewModel> Handle(LoginUserCommand request, CancellationToken cancellationToken)
    {
        var user = await _identityService.GetUserWithMobileAsync(request.PhoneNumber);
        if (user.VerifyCode == request.VerifyCode)
        {

            var res = await _identityService.LoginUser(user);

            user.RefreshToken = res.RefreshToken;
            user.RefreshTokenExpiryTime = res.Expiration;

            user.AddDomainEvent(new DriverLoggedInEvent(user));

            user.VerifyCode = await _identityService.GenerateRandomCode();

//TODO: Here If I use _usermanager.updateuser it no longer returns to (return res) and 
 goes to the DriverLoggedInEventHandler class 

            if (string.IsNullOrEmpty(res.Token))
            {
                return new ResponseLoginViewModel();
            }
            return res;
        }
        return new ResponseLoginViewModel();
    }
}


2:我的 ApplicationUser class 继承自 IdentityUser 和我创建的接口:IEntityWithDomainEvent。

public interface IEntityWithDomainEvent
{
    IReadOnlyCollection<BaseEvent> DomainEvents { get; }
    void AddDomainEvent(BaseEvent domainEvent);
    void RemoveDomainEvent(BaseEvent domainEvent);
    void ClearDomainEvents();
}

但是我不能在savechange的时候put.Entries(),所以我现在用最愚蠢的方式传递了它。

public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
        {
            try
            {
                await _mediator.DispatchDomainEvents(this);

                return await base.SaveChangesAsync(cancellationToken);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                throw new Exception(e.Message);
            }
         
        }

调度域事件:

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

        // TODO : Problem two is solved for now by the following silly method

        if (domainEvents.Count == 0)
        {
            var entities2 = context.ChangeTracker
               .Entries<ApplicationUser>()
               .Where(e => e.Entity.DomainEvents.Any())
               .Select(e => e.Entity);

            domainEvents = entities2
                .SelectMany(e => e.DomainEvents)
                .ToList();
            entities2.ToList().ForEach(e => e.ClearDomainEvents());
        }


        foreach (var domainEvent in domainEvents)
            await mediator.Publish(domainEvent);
    }
}

预先感谢您的帮助

Update1:在 LoginUserCommandHandler 中:请阅读 TODO 部分。 问题出在 TODO 部分的 DispatchDomainEvent 部分。 LoginUserCommandHandler中用_usermanager.updateuser更新用户后,因为数据库保存了,所以LoginUserCommandHandler中return res的值没有返回

不确定实际问题是什么,但至于DispatchDomainEvents似乎BaseEntity应该实现IEntityWithDomainEvent如果它实现了 - 你可以使用简化实现的接口:

public static async Task DispatchDomainEvents(this IMediator mediator, DbContext context)
{
    var entities = context.ChangeTracker
        .Entries<IEntityWithDomainEvent>()
        .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)
        await mediator.Publish(domainEvent);
}

entities的双重枚举也可能不理想,因此:

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

    foreach (var entity in entities)
    {
        foreach (var domainEvent in entity.DomainEvents)
        {
            await mediator.Publish(domainEvent);
        }

        entity.ClearDomainEvents();
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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