Another from the “wicked awesome” category of AutoMapper. Other blogs about AutoMapper and LINQ:
- Efficient querying with LINQ, AutoMapper and Future queries
- Using AutoMapper to prevent SELECT N+1 problems
- Using AutoMapper to perform LINQ aggregations
One current limitation of ORM LINQ projections in general is that it can’t project computed properties:
If you try this using LINQ, you’ll get some error in your LINQ provider about not being able to use a computed property in an expression. Your options at this point are to duplicate the computed property on the destination type, to switch over to the regular Mapper.Map call, or modify your ORM such that the database column itself is defined as a computed column. All of these are fairly intrusive.
But wait, all is not lost! What if we could peer inside the computed property, examine what it’s doing, and include that in our LINQ projection? That sounds hard, but luckily someone has already figured it out in the DelegateDecompiler project.
So how might we put this together? First, we’ll reference the NuGet package for the DelegateDecompiler project
Next, let’s create an extension method for AutoMapper to make it easy to wrap our projection calls with the delegate decompilation:
See that extra “Decompile” method? That’s modifying our existing expression tree that AutoMapper built and replacing computed properties with our own. Underneath the covers, it’s taking this LINQ expression:
And replacing it with this:
The only change to our models was to indicate to the delegate decompiler that this is a computed property. In our domain model, we decorate with the Computed attribute, and now everything works!
Looking at the underlying SQL generated, since the LINQ provider can understand that LINQ expression, we’ll see something like:
I can build computed properties on my domain model, project them automatically using AutoMapper, and have computed properties evaluated all the way down at the database tier with that opt-in “Computed” attribute.
That, I think, is wicked awesome.