#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 в строку, я уверен, что он будет работать
Вставив код в строку, решите проблему