C
C#12mo ago
neSHa

✅ AutoMapper and Expression

So how do i create map for Expression<Func<T,bool>> to Expression<Func<TDto,bool>> for example
34 Replies
Angius
Angius12mo ago
Why would you want to map that? Automapper, generally, is useful mostly for simple mappings Mapping expressions seems way out of it's scope
neSHa
neSHa12mo ago
For example you have getAll(Expression) in your repository that repository is working with T Now we have Commands and handlers and they work with TDto So handler get Expression<Func<TDto,bool>>
Angius
Angius12mo ago
Yeah, so you map from T to TDto
neSHa
neSHa12mo ago
but repository needs Expression<Func<T,bool>>
Angius
Angius12mo ago
await stuff.Where(your_expression).MapTo<TDto>().ToListAsync();
await stuff.Where(your_expression).MapTo<TDto>().ToListAsync();
or some such You map the result, not the expression
neSHa
neSHa12mo ago
mhm, i have expression that i get from request, handler gets it and that expresion is Expression<Func<TDto,bool>>, now if i want to call repository i need Expression<Func<T,bool>> So the only way is to map that
Angius
Angius12mo ago
That seems way overengineered for my liking, I'm already lost lol
neSHa
neSHa12mo ago
or is there way to change expression just that T part
Angius
Angius12mo ago
I just inject DbContext into my query handlers and done
neSHa
neSHa12mo ago
i would do that too yes, but arhitectures and stuff I dont like it either
Angius
Angius12mo ago
A.k.a. "writing code for the sake of writing code"
neSHa
neSHa12mo ago
Im writing mathematicaly correct code xD
Angius
Angius12mo ago
Yeah, sorry, I've never seen expressions being mapped with automapper I barely use automapper in the first place
neSHa
neSHa12mo ago
I didnt even know i can do that
Angius
Angius12mo ago
In my eyes, it's something wrong with your architecture if you need to map expressions
neSHa
neSHa12mo ago
but it seems like its possible I mean, there is other ways to do that, but its way to harder, this is lazy option i mean if we look at filtrering data Expressions are best
Angius
Angius12mo ago
Yeah
neSHa
neSHa12mo ago
I really cant have 100 handlers for that
Angius
Angius12mo ago
So you pass a predicate that takes a T
neSHa
neSHa12mo ago
filter for adress
Angius
Angius12mo ago
You never map it to another expression
neSHa
neSHa12mo ago
Thats cheating
Angius
Angius12mo ago
You just map the result of the filtering how
neSHa
neSHa12mo ago
Repository will broke then so if i got in request Expression<Func<TDto,bool>> and mt rep need Expression<Func<T,bool>> i cant just change rep to get Expression<Func<TDto,bool>>
Angius
Angius12mo ago
I guess you could do the filtering later...?
neSHa
neSHa12mo ago
Wdym by that
Angius
Angius12mo ago
await stuff
.MapTo<TDto>()
.Where(the_expression) // here it's a collection of TDto
.ToListAsync();
await stuff
.MapTo<TDto>()
.Where(the_expression) // here it's a collection of TDto
.ToListAsync();
So the_expression can be <TDto, bool>
neSHa
neSHa12mo ago
lets look that this way hanlder prepare the expresion bla bla and in repository i just .Where(the_expression) // here it's a collection of TDto .ToListAsync();\ I think i need to know how to manipulate expressions If i can manipulate expression to go from T to Tdto thats just one of parameters who knows, i guess it will be never forgoten bettle
Angius
Angius12mo ago
I'd say you're much better off mapping the type first, then using the expression
neSHa
neSHa12mo ago
i mapped that way back but need the expressions to
Angius
Angius12mo ago
In that case, yeah, I've no clue Good luck and mercy on your soul And my condolences that you have to do all that
neSHa
neSHa12mo ago
Thanks, i guss thats the best way to learn something the more i look around the more i found out if you are intrested in solution: public class ExpressionManipulator { public Expression<Func<T, bool>> ConvertToTExpression(Expression<Func<TDto, bool>> sourceExpression) { var parameter = Expression.Parameter(typeof(T), sourceExpression.Parameters[0].Name); var body = new TExpressionVisitor(parameter).Visit(sourceExpression.Body); var TExpression= Expression.Lambda<Func<T, bool>>(body, parameter); return TExpression; } private class TExpressionVisitor : ExpressionVisitor { private readonly ParameterExpression _parameterExpression; public TExpressionVisitor(ParameterExpression parameterExpression) { _parameterExpression = parameterExpression; } protected override Expression VisitParameter(ParameterExpression node) { return _parameterExpression; } protected override Expression VisitMember(MemberExpression node) { if (node.Member.DeclaringType == typeof(TDto)) { var memberName = node.Member.Name; var targetMember = typeof(T).GetProperty(memberName); if (targetMember != null) { return Expression.MakeMemberAccess(_parameterExpression, targetMember); } } return base.VisitMember(node); } } }
Angius
Angius12mo ago
I'm actually impressed a solution exists lol And it doesn't even seem to involve reflections or unsafe blocks!
neSHa
neSHa12mo ago
i know i need to manipulate expression so i guess i did it thats it for next month, im not doing something like this agian