Priyan Perera
Priyan Perera

Reputation: 560

Unable to cast object of type 'System.Collections.Generic.List`1[]' to type 'System.Linq.IQueryable`1[]'

I have got the following code in my unit test. But, it returns the error mentioned when run.

var leaveTypesList = new List<LeaveType>() { leaveType1, leaveType2, leaveType3 };
var leaveTypesQueryable = leaveTypesList.AsQueryable();
mockLeaveTypeRepository.Setup(r => r.GetLeaveTypes()).Returns(leaveTypesQueryable);
var leaveTypeDtos = service.GetLeaveTypes();

The error is generated from the last line when the results are returned from the service.

The service code for the GetLeaveTypes method listed below, which is a simple accessing of the repository.

    public IQueryable<LeaveTypeDto> GetLeaveTypes()
    {
        //return Mapper.Map<IQueryable<LeaveTypeDto>>(leaveTypeRepository.GetLeaveTypes());
        return leaveTypeRepository.GetLeaveTypes().ProjectTo<LeaveTypeDto>();
    }

The repository code is also a simple return of an IQueryable of leave types.

    public IQueryable<LeaveType> GetLeaveTypes()
    {
        return dbContext.LeaveType.Where(lt => lt.IsActive);
    }

Just cannot figure out what is wrong here. Any ideas?

Upvotes: 1

Views: 8083

Answers (1)

Gert Arnold
Gert Arnold

Reputation: 109119

You want to map leaveTypeRepository.GetLeaveTypes() to an IQueryable of the matching DTO object. I assume you want this because leaveTypeRepository.GetLeaveTypes() is an IQueryable too and you want to stay in touch with its query provider.

AutoMapper has a different method for this:

using AutoMapper.QueryableExtensions;

...

return leaveTypeRepository.GetLeaveTypes()
           .ProjectTo<LeaveTypeDto>();

This returns an IQueryable<LeaveTypeDto>, to which you can apply subsequent LINQ methods, that will still be translated into SQL.

And now the reason of the exception. It's because there isn't a default implementation for IQueryable<T>. AutoMapper creates List<LeaveTypeDto>, but that can't natively be converted into IQueryable<LeaveTypeDto>. You can however do things like ...

Mapper.Map<IEnumerable<LeaveTypeDto>>(source)
Mapper.Map<IList<LeaveTypeDto>>(source)
Mapper.Map<LeaveTypeDto[]>(source)

... because for those target types AutoMapper knows which default implementation it should use (List<T> or T[]).

Upvotes: 2

Related Questions