首页 > 解决方案 > 如何避免“System.InvalidOperationException:客户端投影包含对常量表达式的引用”错误?

问题描述

我正在编写一个 C# .NET 5 应用程序,它将充当 Angular 前端的后端,提供 CRUD API。该应用程序的目的是管理飞行学校。

我正在编写将返回飞行员列表和单个飞行员的 API 方法,即https://myapp/api/pilotsand https://myapp/api/pilots/{id}

我这里有三种方法:

  1. GetPilots()完整列表
  2. GetPilot(long idPilot)详情
  3. 一种辅助方法GetFlightTime(long idPilot),用于返回每个飞行员的总飞行时间,以及飞行持续时间的总和。

我的问题:detail 方法有效,因为我首先调用辅助函数,然后在返回的视图模型中使用结果。但GetPilots()不起作用并返回错误System.InvalidOperationException: The client projection contains a reference to a constant expression of 'QTBWeb.Models.PilotsRepository' through the instance method 'GetFlightTime'. This could potentially cause a memory leak; consider making the method static so that it does not capture constant in the instance.

这是因为我GetFlightTime在 LINQ 表达式中调用该方法吗?我不明白使方法静态建议。如何重新格式化代码以使其正常工作?

谢谢!

   public IEnumerable<PilotViewModel> GetPilots()  // THIS METHOD RETURNS ERROR
    {
        return _context.Pilots
            .Select(pilot => new PilotViewModel
            {
                Id = pilot.Id,
                Name = pilot.Name,
                FlightMinutes = GetFlightTime(pilot.Id)  // THE PROBLEM IS HERE
            })
            .ToList();
    }

    public PilotViewModel GetPilot(long idPilot)  // THIS METHOD WORKS
    {
        var _flightMinutes = GetFlightTime(idPilot);

        return _context.Pilots
            .Select(pilot => new PilotViewModel
            {
                Id = pilot.Id,
                Name = pilot.Name,
                FlightMinutes = _flightMinutes
            })
            .Where(pilot => pilot.Id == idPilot)
            .FirstOrDefault();
    }

    public int GetFlightTime(long idPilot)
    {
        return _context.Flights
            .Where(flight => flight.pilot == idPilot)
            .Select(flight => flight.Duration).Sum();  
    }

标签: c#restlinq

解决方案


解决这个问题的一个好方法是确保你的Pilot类有一个集合Flights,作为你拥有的一对多映射的另一面Flight.Pilot。然后,您可以使用此集合来计算总和,而无需查询数据库中的每个循环实例Pilot

您的代码将如下所示:

public IEnumerable<PilotViewModel> GetPilots()
    {
        return _context.Pilots
            .Include(pilot => pilot.Flights) // Include Flights to join data
            .Select(pilot => new PilotViewModel
            {
                Id = pilot.Id,
                Name = pilot.Name,
                FlightMinutes = pilot.Flights.Sum(flight => flight.Duration)
            });
    }

    public PilotViewModel GetPilot(long idPilot)
    {
        return _context.Pilots
            .Include(pilot => pilot.Flights) // Include Flights to join data
            .Where(pilot => pilot.Id == idPilot) // Notice how we filter first
            .Select(pilot => new PilotViewModel
            {
                Id = pilot.Id,
                Name = pilot.Name,
                FlightMinutes = pilot.Flights.Sum(flight => flight.Duration)
            })
            .FirstOrDefault();
    }

推荐阅读