'Collection.AsQueryable() returns NullReferenceException when mapping with AutoMapper

I am still a bit new to programming. I have the following method in my LessonsService:

public async Task<IEnumerable<T>> GetUserLessonsTableDataAsync<T>(string userId, string sortColumn, string sortColumnDirection, string searchValue)
{
    var user = await this.usersRepository
        .AllAsNoTracking()
        .Include(x => x.Trainer)
        .ThenInclude(t => t.Lessons)
        .Include(x => x.Member)
        .ThenInclude(m => m.Lessons)
        .ThenInclude(lm => lm.Lesson)
        .FirstOrDefaultAsync(x => x.Id == userId);

    IQueryable<Lesson> lessons;

    if (user.Trainer != null)
    {
        lessons = user.Trainer.Lessons.AsQueryable();
    }
    else
    {
        var lessonsMembers = user.Member.Lessons.Where(x => x.MemberId == user.MemberId);
        var lessonsList = new List<Lesson>();

        foreach (var lessonMember in lessonsMembers)
        {
            lessonsList.Add(lessonMember.Lesson);
        }

        lessons = lessonsList.AsQueryable();
    }

    var lessonData = from lesson in lessons select lesson;

    if (!(string.IsNullOrEmpty(sortColumn) && string.IsNullOrEmpty(sortColumnDirection)))
    {
        lessonData = lessonData.OrderBy(sortColumn + " " + sortColumnDirection);
    }

    if (!string.IsNullOrEmpty(searchValue))
    {
        lessonData = lessonData.Where(l => l.Topic.Contains(searchValue)
                            || l.StartingTime.Equals(searchValue)
                            || l.Group.Name.Contains(searchValue)
                            || l.Trainer.User.FirstName.Contains(searchValue)
                            || l.Trainer.User.LastName.Contains(searchValue));
    }

    return lessonData.To<T>().ToList();
}

For some reason this code throws System.NullReferenceException with message "Object reference not set to an instance of an object". I debugged and noticed that lessonData is not null, it is full with data from the database. Apparently, the mapping method .To< T >() is not working properly as it returns the following:

Results view screenshot

My controller is:

[HttpPost]
public async Task<IActionResult> GetUserLessons()
{
    try
    {
        var userId = this.HttpContext.Session.GetString("userId");
        var draw = this.Request.Form["draw"].FirstOrDefault();
        var start = this.Request.Form["start"].FirstOrDefault();
        var length = this.Request.Form["length"].FirstOrDefault();
        var sortColumn = this.Request.Form["columns[" + this.Request.Form["order[0][column]"].FirstOrDefault() + "][name]"].FirstOrDefault();
        var sortColumnDirection = this.Request.Form["order[0][dir]"].FirstOrDefault();
        var searchValue = this.Request.Form["search[value]"].FirstOrDefault();
        int pageSize = length != null ? Convert.ToInt32(length) : 0;
        int skip = start != null ? Convert.ToInt32(start) : 0;
        int recordsTotal = 0;

        var lessonData = await this.lessonsService.GetUserLessonsTableDataAsync<LessonViewModel>(userId, sortColumn, sortColumnDirection, searchValue);

        recordsTotal = lessonData.Count();

        var data = lessonData.Skip(skip).Take(pageSize).ToList();
        var jsonData = new { draw, recordsFiltered = recordsTotal, recordsTotal, data };

        return this.Ok(jsonData);
    }
    catch (Exception e)
    {
        throw;
    }
}

The exception message in the stack trace is the following:

   at System.Linq.Enumerable.SelectIPartitionIterator`2.MoveNext()
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at ChessBurgas64.Services.Data.LessonsService.<GetUserLessonsTableDataAsync>d__15`1.MoveNext() in F:\ChessclubBurgas64WebApp\ChessBurgas64\Services\ChessBurgas64.Services.Data\LessonsService.cs:line 211
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at ChessBurgas64.Web.Controllers.UsersController.<GetUserLessons>d__17.MoveNext() in F:\ChessclubBurgas64WebApp\ChessBurgas64\Web\ChessBurgas64.Web\Controllers\UsersController.cs:line 171

I have a static class (where the method .To< T >() is positioned) that is referenced in the lessonsService:

public static class QueryableMappingExtensions
{
    public static IQueryable<TDestination> To<TDestination>(
        this IQueryable source,
        params Expression<Func<TDestination, object>>[] membersToExpand)
    {
        if (source == null)
        {
            throw new ArgumentNullException(nameof(source));
        }

        return source.ProjectTo(AutoMapperConfig.MapperInstance.ConfigurationProvider, null, membersToExpand);
    }

    public static IQueryable<TDestination> To<TDestination>(
        this IQueryable source,
        object parameters)
    {
        if (source == null)
        {
            throw new ArgumentNullException(nameof(source));
        }

        return source.ProjectTo<TDestination>(AutoMapperConfig.MapperInstance.ConfigurationProvider, parameters);
    }
}

Inoticed that this happens only to navigational properties (in this case it's user.Trainer.Lessons). If I get the lessons directly from the repository with lessons = this.lessonsRepository.All().Where(...);, there will be no problem and everything will work fine, because the collection will be then a Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable instead of System.Collections.Generic.HashSet`1[Lesson]. So I guess the problem is that the method .AsQueryable() is not really converting the lessons to Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable, which is needed for the mapping method .To< T >() to work properly? What is the best way to fix this?



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source