简体   繁体   English

如何在 .NET 中使用 CQRS 模式 mediatr 使 EF 事务化?

[英]How to make EF transactional using CQRS pattern mediatr in .NET?

Suppose I have CreateProductCommandHandler :假设我有CreateProductCommandHandler

public class CreateProductCommandHandler : IRequestHandler<CreateProductCommand, Guid>
    {
        private readonly IProductRepository _productRepository;
        private readonly IProductCategoryRepository _productCategoryRepository;
        private readonly IMapper _mapper;
        private readonly IEmailService _emailService;

        public CreateProductCommandHandler(IEmailService emailService, IProductRepository productRepository, IMapper mapper, IProductCategoryRepository productCategoryRepository)
        {
            _mapper = mapper;
            _productRepository = productRepository;
            _emailService = emailService;
            _productCategoryRepository = productCategoryRepository;
        }

        public async Task<Guid> Handle(CreateProductCommand request, CancellationToken cancellationToken)
        {
            var validator = new CreateProductCommandValidator(_productRepository);
            var validationResult = await validator.ValidateAsync(request);

            if (validationResult.Errors.Count > 0)
                throw new Exceptions.ValidationException(validationResult);


            var @product = _mapper.Map<Product>(request);

            @product = await _productRepository.AddAsync(@product);


            var @productCategory = new ProductCategory();
            @productCategory.ProductID = @product.ProductID;
            foreach (var cat in request.listOfCategories)
            {
                @productCategory.CategoryID = cat.CategoryID;
                await _productCategoryRepository.AddAsync(@productCategory);
            }
            return @product.Uid;
        }
    }

As I am using two repositories, it might occur that at this line当我使用两个存储库时,可能会出现在这一行

await _productCategoryRepository.AddAsync(@productCategory);等待 _productCategoryRepository.AddAsync(@productCategory);

something fail, so I need to do rollback on whole transaction.有些事情失败了,所以我需要对整个事务进行回滚。 As I am new to CQRS mediatr, do someone have idea and best approach to do this?由于我是 CQRS mediatr 的新手,有人有想法和最好的方法来做到这一点吗?

If it's all within the scope of one handler.如果这一切都在一个处理程序的 scope 内。 The simplest solution will be to inject the DbContext and create a transaction wrapping all your repository calls like below.最简单的解决方案是注入 DbContext 并创建一个包含所有存储库调用的事务,如下所示。

public class CreateProductCommandHandler : IRequestHandler<CreateProductCommand, Guid>
{
    private readonly IProductRepository _productRepository;
    private readonly IProductCategoryRepository _productCategoryRepository;
    private readonly SomeDbContext _dbContext;
    private readonly IMapper _mapper;
    private readonly IEmailService _emailService;

    public CreateProductCommandHandler(IEmailService emailService, IProductRepository productRepository, IMapper mapper, IProductCategoryRepository productCategoryRepository, SomeDbContext dbContext)
    {
        _mapper = mapper;
        _productRepository = productRepository;
        _emailService = emailService;
        _productCategoryRepository = productCategoryRepository;
        _dbContext = dbContext;
    }

    public async Task<Guid> Handle(CreateProductCommand request, CancellationToken cancellationToken)
    {
        var validator = new CreateProductCommandValidator(_productRepository);
        var validationResult = await validator.ValidateAsync(request);

        if (validationResult.Errors.Count > 0)
            throw new Exceptions.ValidationException(validationResult);
        

        var @product = _mapper.Map<Product>(request);

        await using var transaction = await _dbContext.Database.BeginTransactionAsync();
        @product = await _productRepository.AddAsync(@product);


        var @productCategory = new ProductCategory();
        @productCategory.ProductID = @product.ProductID;
        foreach (var cat in request.listOfCategories)
        {
            @productCategory.CategoryID = cat.CategoryID;
            await _productCategoryRepository.AddAsync(@productCategory);
        }
        await transaction.CommitAsync();
        return @product.Uid;
    }
}

If an exception occurs before you call CommitAsync() the transaction will be disposed and rollback will happen .如果在您调用 CommitAsync() 之前发生异常,事务将被释放并发生回滚

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

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