17

I'm wondering if there is anything I can do to get this working as expected. This works fine in my code:

        var roles = _securityContext.Set<Role>();
        var roleList = new List<RoleDto>();
        foreach (var role in roles)
        {
            roleList.Add(Mapper.Map<Role, RoleDto>(role)); 
        }

        return roleList;

But changing this to:

        var roles = _securityContext.Set<Role>();

        return roles.Select(role => Mapper.Map<Role, RoleDto>(role)).ToList();

Results in an error I've not seen before:

"LINQ to Entities does not recognize the method 'Security.Dto.RoleDto MapRole,RoleDto' method, and this method cannot be translated into a store expression"

I'm not sure if I can even do anything about this'problem' ... arguably the method that works is more readable anyway ...

Jammer
  • 9,969
  • 11
  • 68
  • 115

1 Answers1

30

You're operating on IQueryable, which tries to translate the method you supply into SQL. Obviously, it's not going to happen, as you're passing AutoMapper related magic. There's an easy solution, you have to force execution before mapping:

return roles.ToList().Select(role => Mapper.Map<Role, RoleDto>(role)).ToList();

[EDIT] As Daniel suggests in comments, you can always go from IQueryable to IEnumerable by calling AsEnumerable() and still defer execution:

return roles.AsEnumerable().Select(role => Mapper.Map<Role, RoleDto>(role)).ToList();
Patryk Ćwiek
  • 14,078
  • 3
  • 55
  • 76
  • 14
    Using `AsEnumerable()` instead of `ToList()` is better as it still will perform deferred execution. – Daniel Hilgarth Feb 08 '13 at 10:58
  • 1
    That has to be the funniest name I've come across online! – Aniket Inge Feb 08 '13 at 11:00
  • @Jammer But be careful when and where you dispose of the context. If you dispose the `DbContext` before materializing the collection (by e.g. calling `ToList()`, you'll get `ObjectDisposedException` when trying to do anything with the result. – Patryk Ćwiek Feb 08 '13 at 11:38
  • @Trustme-I'maDoctor for sure. I generally keep the same context around for the duration of a request and then dispose of it so I shouldn't see this exception! ... famous last words! Thanks! – Jammer Feb 11 '13 at 10:18
  • The [Edit] above says that execution is deferred, however, the the ToList() contradicts that. If deferred execution is desired, then the ToList() should be removed and the result returned should be IEnumerable. – CodeMonkeyKing Nov 27 '13 at 17:47
  • 3
    @CodeMonkeyKing `AsEnumerable` would move it to LINQ to Objects domain and defer execution until the last `ToList()`, while the first example creates two lists one after another. That's the difference. :) – Patryk Ćwiek Nov 27 '13 at 21:53