I'm using Automapper's (8.0) DI pattern in my project and am looking to start using ProjectTo in my Entity Framework Core entity queries.
Here is an example of what I have managed to get to work:
public async Task<IEnumerable<SomeViewModel>> GetStuffAsync() {
return await _dbContext.SomeEntity
.ProjectTo<SomeViewModel>(_mapper.ConfigurationProvider)
.ToListAsync();
}
The above call returns all the expected records but it requires both injecting IMapper
in the constructor of the repository as well as a Using reference to AutoMapper.QueryableExtensions.
There are two versions of the AutoMapper docs that I have found and they seem to provide conflicting info.
These docs https://automapperdocs.readthedocs.io/en/latest/Dependency-injection.html state the following:
Using DI is effectively mutually exclusive with using the
IQueryable.ProjectTo
extension method. UseIEnumerable.Select(_mapper.Map<DestinationType>).ToList()
instead.
And these docs http://docs.automapper.org/en/stable/Dependency-injection.html state this:
Starting with 8.0 you can use
IMapper.ProjectTo
. For older versions you need to pass the configuration to the extension methodIQueryable.ProjectTo<T>(IConfigurationProvider)
.
Following the first documentation's example, I converted my query to this:
public IEnumerable<SomeViewModel> GetStuff() {
return _dbContext.SomeEntity
.Select(_mapper.Map<SomeViewModel>)
.ToList();
}
However, that method returns 0 records (the previous returned everything) and the method needed to be converted from Async to synchronous as ToListAsync() wasn't supported by the extended Select. Clearly I'm missing something. Also, I'm not sure if that is the correct technique as the second set of docs talk about using IMapper.ProjectTo for version 8.0 without passing the configuration to the extension method. How do I do that?
The . ProjectTo<OrderLineDTO>() will tell AutoMapper's mapping engine to emit a select clause to the IQueryable that will inform entity framework that it only needs to query the Name column of the Item table, same as if you manually projected your IQueryable to an OrderLineDTO with a Select clause.
To use AutoMapper first install NuGet. Then, install AutoMapper from the package manager console: PM> Install-Package AutoMapper.
Starting with 8.0 you can use IMapper.ProjectTo
This means that now IMapper
interface has a method ProjectTo
(similar to Map
). So while you still need injecting IMapper
(but you need it anyway if you were using Map
, so no difference), you don't need QueryableExtensions
and ProjectTo
extension method - you simply use the interface method (similar to Map
):
return await _mapper.ProjectTo<SomeViewModel>(dbContext.SomeEntity)
.ToListAsync();
Please note that there is fundamental difference between _mapper.ProjectTo
and Select(_mapper.Map)
- the former is translated to SQL and executed server side, while the latter leads to client evaluation and needs Include
/ ThenInclude
(or lazy loading) in order to function properly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With