Question

I have a situation in AutoMapper where I need to create a mapping with an interface destination. This is not a problem, and when using the normal Mapper.Map, it returns a proxy class as expected. However, when I try to do something similar with .Project().To(), which I need to use because an ORM is involved, I have issues. Here is the exact code that is failing which I replicated in a unit test:

AutoMapper.Mapper.CreateMap<RoleDto, IRole>(); //both just have Id/Name

IQueryable<RoleDto> roleDtos = new List<RoleDto>
{
    new RoleDto { Id = 1, Name = "Role1" },
    new RoleDto { Id = 2, Name = "Role2" }
}.AsQueryable();

//this works:
List<IRole> roles = roleDtos.Select(
    roleDto => AutoMapper.Mapper.Map<IRole>(roleDto)
    ).ToList();

//this does not work:
List<IRole> roles2 = roleDtos.Project().To<IRole>().ToList();

I'm getting ArgumentException:

ArgumentException: Type 'UnitTestProject5.IRole' does not have a default constructor

In my real implementation the .Select is being performed on an Entity Framework collection, which is why I need to stick with .Project().To().

I have no issues with .Project().To() if the destination is not an interface. Additionally, I have no issues with the interface destination if I use .Map().

How can I get the interface destination and .Project.To() to work at the same time? Why is .Project.To() not giving me proxy classes like .Map() is? Any ideas?

Thanks!

Was it helpful?

Solution

Mapper.Map() takes the linq-to-objects route to materialize objects. As you said, AutoMapper is capable of creating types on the fly if the mapped target is an interface.

Project().To() is a way to translate the whole query, including the mapping, into SQL. Which is great, because only the properties that are required for the target object are included in the SQL query. However, the things AutoMapper does for creating types on the fly (undoubtedly some Refection voodoo) can never be part of an expression tree that can be converted into SQL. That's why Project.To simply tries to new up an object, even if it's an interface.

You'll have to use a concrete type as a mapping target. Of course, this type can implement an interface, so you can keep the independence you want.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top