Closed andrew1555 closed 1 year ago
Thats actually I problem I encountered too. Did not find another solution yet as it would introduce a new layer in the architecture which then makes the whole thing useless.
Hi. There is no easy way to share logic between CQRS handlers. What can I suggest:
What do you think about these approaches?
Hi
Thanks for your answers, I'm not a fan on the first 3 tbh but the 4th is similar to what I've been doing. I've created a application service for each separate feature which looks like
public class SizeConversionsService : ISizeConversionsService
{
private readonly IMediator _mediator;
public SizeConversionsService(IMediator mediator)
{
_mediator = mediator;
}
public async Task<List<SizeConversionResult>> GetSizeConversion(SizingType type)
{
return await _mediator.Send(new GetSizeConversionsQuery { Type = type });
}
}
But in my case I was still using queries via mediator to benefit from the pipelines, I have a cache pipeline which saves the result in redis, so the query is in charge of cache duration etc. I then inject the ISizeConversionsService into any usecase which needs to know about sizes. With it being a service too like you say I'm able to inject in other things like current user, currency, settings etc.
My handlers would then look like this
public class Handler : IRequestHandler<GetBuyGridQuery, BuyGrid>
{
private readonly ISizeConversionsService _sizeConversionsService;
}
To solve my repeated sql call issue I added in caching into the handler. So for example I have a query which gets a product based on productId but a sub query would get the category, since we have far fewer categories than products repeatedly getting the same category from the database would add up to around 5k identical db calls an hour so I placed it around a cache
var category = await _cacheManager.GetOrCreateAsync($"GetProductByUrlQuery:GetCategory:CategoryId_{productResult.Product.CategoryId}",
() => GetCategory(productResult.Product.CategoryId), 3600);
This way repeated calls to the usecase for different products wouldn't result in the same sql query to get the same category, if that makes sense. I could have solved it using a application service instead and then caching would be shared if any other usecase needed it also, but wasn't sure which solution was better.
What do you think?
I also came across this link https://lostechies.com/jimmybogard/2016/12/12/dealing-with-duplication-in-mediatr-handlers/ which offers some alternatives also
Thanks
Hi
So you wrap mediator calls by the application services. It is item No1 in my list of suggestions. Why do you need this abstraction? I believe you can inject a mediator into the handler. Less code => less bugs (and abstraction layers).
And I totally agree with Jimmy about his article. How to deal with duplicated logic - it depends... There are too many different kinds of logic: data access, domain, or application logic. But if I understand correctly we are talking about the application logic.
PS: you can make your handlers internal
because they are not a part of the Application Layer contract (Contract = Commands/Queries + DTO).
PPS: When you use GetOrCreateAsync it does not guarantee that GetCategory will be called exactly once.
Great thank you for your reply, I was under the impression injecting mediator into the handlers and calling other handlers would go against the recommendation, do you think it's no different then to using a service class which then calls mediator. The thinking behind it was it was then a single location which calls the query handler everywhere else uses the service so if I needed to change how it's called it would be a single place.
Do you have any working examples of reusing queries in a clean way. Jimmy talks about methods in the dbContext but then how would do this with dapper like data calls.
Thanks for the tip on internal keyword will give that a go.
Thank you for your interest in this project. This repository has been archived and is no longer actively maintained or supported. We appreciate your understanding. Feel free to explore the codebase and adapt it to your own needs if it serves as a useful reference. If you have any further questions or concerns, please refer to the README for more information.
Hi
What is the best way to deal with duplication within a query, for example say we have a currency object which each use cases needs. It feels wrong to call a query from a query, and feels wrong to repeat the code in each one too, if our logic on currency changes we would then have a lot of places to change.
Also from a performance point of view we want to cache repeated queries, so if a query contains a database call which could be cached if the query was to be ran again with different parameters, would we cache this within the query or refactor it out into some sort of repository.
Any ideas would be welcome
Thanks