#c# #entity-framework #cqrs #mediatr
Вопрос:
Предположим, у меня есть 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;
}
}
Поскольку я использую два репозитория, может случиться так, что в этой строке
ожидание _продукткатегориярепозиционная.addAsync(@Категория продукта);
что-то не получается, поэтому мне нужно выполнить откат всей транзакции. Поскольку я новичок в CQRS mediatr, у кого-нибудь есть идея и лучший подход для этого?
Комментарии:
1. Ссылаются ли оба репозитория на одну и ту же базу данных, используя одну и ту же строку подключения? Если нет, то вы весело проведете время , координируя распределенную транзакцию , в зависимости от операционной системы, базы данных и платформы
Ответ №1:
Если все это находится в пределах одного обработчика. Самым простым решением будет ввести 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;
}
}
Если до вызова функции commitAsync() возникнет исключение, транзакция будет удалена и произойдет откат.