Collection.AsQueryable() 在使用 AutoMapper 映射时返回 NullReferenceException

Collection.AsQueryable() returns NullReferenceException when mapping with AutoMapper

提问人:Daniel Ninchev 提问时间:5/12/2022 最后编辑:Svyatoslav DanylivDaniel Ninchev 更新时间:5/13/2022 访问量:338

问:

我对编程还有点陌生。我的 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();
}

出于某种原因,此代码会引发 System.NullReferenceException,并显示消息“对象引用未设置为对象的实例”。我调试并注意到 lessonData 不是 null,它充满了来自数据库的数据。显然,映射方法.To< T >() 无法正常工作,因为它返回以下内容:

Results view screenshot

我的控制器是:

[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;
    }
}

堆栈跟踪中的异常消息如下:

   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

我有一个静态类(其中方法.To< T >() 被定位),在 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);
    }
}

我注意到这仅发生在导航属性上(在本例中为用户。Trainer.Lessons))。 如果我直接从存储库中获取课程,lessons = this.lessonsRepository.All()。Where(...);,不会有问题,一切都会正常工作,因为集合将是 Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable 而不是 System.Collections.Generic.HashSet'1[Lesson]。所以我想问题在于方法.AsQueryable() 并没有真正将课程转换为 Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable,这是映射方法所必需的。要< >() 才能正常工作?解决此问题的最佳方法是什么?

C# LINQ 实体框架核心 自动映射器 NullReferenceException

评论

0赞 Panagiotis Kanavos 5/12/2022
AutoMapper 在哪里调用?将返回的实际完整异常文本作为文本发布在问题本身中。您应该认真考虑使用“存储库”模式是否在这里提供了任何内容,或者使它无法理解此代码的作用。毕竟,您有很多特定于 EF 的调用,例如 和 ,因此您没有抽象任何内容Exception.ToString()IncludeAllAsNoTracking
0赞 Panagiotis Kanavos 5/12/2022
代码没有对 EF Core 的调用。也不清楚错误在哪里引发。错误很可能是正确的 - 加载的对象有一些空的导航属性,因此当 Automapper 尝试使用这些缺失实体的属性时,它会抛出
0赞 Daniel Ninchev 5/12/2022
感谢您的回复。请原谅我,我对编程有点陌生,所以我的帖子有点混乱。我编辑并添加了更多代码。我看到您将存储库模式称为“反模式”,这让我很感兴趣,因为我看到了关于这个主题的不同意见。您能否提供更多关于为什么使用存储库模式不好的信息?谢谢。
0赞 joakimriedel 5/16/2022
您正在寻找 Query() 而不是 AsQueryable(),它在这里对您没有任何好处。请参阅 learn.microsoft.com/en-us/ef/core/querying/related-data/...,了解如何对实体跟踪器中已有的集合/引用编写查询。

答: 暂无答案