EF Основной динамический лямбда-подзапрос не работает

#c# #entity-framework-core

Вопрос:

У меня проблема с некоторыми динамически созданными IQueriable<T> , которые позже используются в качестве подзапроса к другому запросу.Я постараюсь объяснить:

Я использую метод, который возвращает IQueryable :

 private IQueryable<ProcessValueBase> GetQuery(string period, DeviceModel device)
        {
            var predicatePv = PredicateBuilder.New<ProcessValueModel>()
                .And(pv => pv.TagSettings.DeviceId == device.Id)
            .And(GetSetpointCommonExpression<ProcessValueModel>(GetSetpointTagTypeId(device.DeviceTypeId)));
            var predicateNv = PredicateBuilder.New<NormalizedLogValueModel>()
                .And(pv => pv.TagSettings.DeviceId == device.Id)
            .And(GetSetpointCommonExpression<NormalizedLogValueModel>(GetSetpointTagTypeId(device.DeviceTypeId)));

            var utcTime = DateTime.Now.ToUniversalTime();
            switch (period)
            {
                case TimePeriodType.Current:
                    return dbContext.ProcessValues.Where(predicatePv);
                case TimePeriodType.Day:
                    var startOfDay = utcTime.StartOfDay();
                    predicateNv = predicateNv.And(v => v.Timestamp >= startOfDay amp;amp; v.Timestamp < startOfDay.AddDays(1));
                    break;
                case TimePeriodType.Week:
                    var startOfWeek = utcTime.FirstDayOfWeek();
                    predicateNv = predicateNv.And(v => v.Timestamp >= startOfWeek amp;amp; v.Timestamp < startOfWeek.AddDays(7));
                    break;
                case TimePeriodType.Month:
                    var startOfMonth = utcTime.FirstDayOfMonth();
                    predicateNv = predicateNv.And(v => v.Timestamp >= startOfMonth amp;amp; v.Timestamp < startOfMonth.AddMonths(1));
                    break;
                default:
                    break;
            }
            return dbContext.NormalizedLogValues.Where(predicateNv);
        }
 

Затем я использую его в своем основном запросе:

 var res = dbContext.Rooms.Select(r => new
            {
                RoomId = r.Id,
                ZoneId = r.ZoneId,
                IdealSetpoint = r.Group.Setpoints.First(sp => sp.ClimaticZoneId == dbContext.ClimaticZonesLogs.OrderByDescending(cz => cz.Timestamp).First().ClimaticZoneId).Setpoint,
                Devices = r.Devices
                .Select(rd => rd.Device)
                .Select(d => new
                {
                    Id = d.Id,
                    Name = d.Name,
                    //Here is the problem
                    Setpoint = GetQuery(req.Period, d).Average(t => t.Value)
                })
            }
            ).ToList();
 

Исключение, которое я получаю, это:

 The LINQ expression 'SetpointSideViewHandler.GetQuery(
    period: __req_Period_0, 
    device: NavigationTreeExpression
        Value: EntityReference: DeviceModel
        Expression: d.Inner)
    .Average(t => t.Value)' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'.
 

У кого-нибудь есть догадка, почему я получаю эту ошибку?

Заранее спасибо,

Джулиан

Комментарии:

1. Вы не говорите, какой поставщик LINQ вы используете, но в целом поставщики LINQ не являются волшебными ; всегда будет предел тому, насколько интересен C#, который они могут успешно конвертировать для запуска в магазине

2. Вы в принципе не можете вызывать /любую/ функцию внутри a .Select и ожидать, что она будет запущена на сервере. Если вы вставите свой код GetQuery в строку, я уверен, что он будет работать

3. @Neil дело в том, что мне нужно «брать» информацию из другого DbSet<T> контекста, основываясь на (в моем случае) d во втором .Select . Но да, я понял твою точку зрения

Ответ №1:

Как сказал @Neil в комментариях, мы не можем вводить вызов какой-либо функции .Select :

Вы в принципе не можете вызвать /любую/ функцию в a .Выберите и ожидайте, что он будет запущен на сервере. Если вы вставите свой код GetQuery в строку, я уверен, что он будет работать

Вставив код в строку, решите проблему