У меня есть эта функция, которая возвращает IQueryable
:
private IQueryable<string> GetActiveCellPhoneNumbersUpToDate(long serviceToken, DateTime date, bool? isPrepaid = null)
{
var to = date.AddDays(1).Date;
var query = ViewRepository
.All
.Where(i => i.ServiceToken == serviceToken)
.Where(i => i.Date < to);
if (isPrepaid.HasValue)
{
query = query.Where(i => i.IsPrepaid == isPrepaid);
}
query = query.OrderByDescending(i => i.Date);
var result = query
.GroupBy(i => i.CellPhoneNumber)
.Where(i => i.First().ActionId == (int)SubscriptionAction.Subscription)
.SelectMany(i => i.ToList())
.Select(i => i.CellPhoneNumber)
.Distinct();
return result;
}
и эта функция будет называться другой функцией только для подсчета:
var prepaidsCount = GetActiveCellPhoneNumbersUpToDate(serviceToken, DateTime.Date, true);
var postPaidsCount = GetActiveCellPhoneNumbersUpToDate(serviceToken, DateTime.Date, false);
И когда я его выполняю, я вижу критическое изменение EF 3.0, в котором говорится:
Обработка выражения LINQ 'i => i .ToList()' с помощью 'NavigationExpandingExpressionVisitor' не удалась. Это может указывать либо на ошибку, либо на ограничение в EF Core. См. https://go.microsoft.com/fwlink/?linkid=2101433. для получения более подробной информации.
Как указано в примечаниях о критических изменениях, мне нужно использовать AsEnumerable
или ToList
перед сложными предложениями Where
, чтобы выполнить эту часть LINQ и перенести данные в ОЗУ, а затем продолжить мой запрос.
Но для больших объемов данных с необходимостью динамических запросов это абсолютно безумно и невообразимо неэффективно.
Чем заменить это? Как мы можем создавать динамические сложные запросы, которые будут транслироваться во время выполнения и возвращать только единственное скалярное значение?
Обновление. Реальные требования — это не приветственные примеры. Им нужна сложная фильтрация, сортировка, группировка и другие функции, смешанные вместе, для извлечения данных из реляционной структуры. Раньше для этих целей мы использовали хранимые процедуры. Передача пары параметров в базу данных и написание уродливого, сложно тестируемого, далеко не поддерживаемого, еженедельно набираемого, устойчивого к рефакторингу SQL-кода для выборки данных.
Теперь единственный вариант, который приходит мне на ум, — вернуться к этим уродливым хранимым процедурам. Является ли этот кошмар реальностью в EF 3.1?
Обновление 2: это мой сценарий. У меня есть таблица, в которой я храню подписку/отмену номера сотового телефона в определенных службах. Упрощенная версия этой таблицы будет выглядеть так:
create table Subscriptions
(
Id,
CellPhoneNumber,
ServiceId,
Date,
ActionId
)
И это могут быть записи:
John,+1-541-754-3010,15,2019-10-13 12:10:06.153,1
John,+1-541-754-3010,15,2019-10-18 12:10:06.153,2
Здесь мы видим, что Джон подписался на услугу 15 и оставался в ней 5 дней, а затем отменил. Если мы хотим сообщить, сколько подписчиков у нас было на 2019-10-14, будет учитываться Джон. Потому что в то время его последним действием было зачисление. Но если мы хотим сообщить, сколько у нас было подписчиков на 2910-11-03
, то последним действием Джона был выход из сервиса, и его не следует учитывать.
.SelectMany(i => i.ToList())
? Как это можно перевести в SQL? Что это вообще значит? Результаты SQL не вложены, им не нужен SelectMany - person Panagiotis Kanavos   schedule 13.12.2019.Where(i => i.First().ActionId == (int)SubscriptionAction.Subscription)
в группе? Похоже, он пытается разгруппировать группу и выбрать случайныйActionId
. В SQL вы должны использоватьGROUP BY
и либо MIN(ActionID)`, либоMAX(ActionID)
для получения первого или последнего идентификатора, или оконную функцию, такую какFirst_Value
илиLast_Value
- person Panagiotis Kanavos   schedule 13.12.2019ActionId
, это первоеActionId
с этого момента или, другими словами, последнее действие, предпринятое подписчиком. Если последним его действием была подписка, то он в сервисе, тогда мы его засчитываем. - person mohammad rostami siahgeli   schedule 13.12.2019GROUP BY
просто потому, что данные исчезли — это либо ключи, либо агрегаты. Единственная причина, по которой ваш запрос работал раньше, заключается в том, что данные не были сгруппированы в базе данных. - person Panagiotis Kanavos   schedule 13.12.2019GetIfExists
,GetByGuid
илиGetList(List<long> ids)
, или другие удобные методы отсутствуют в интерфейсе EF Core. Таким образом, мы должны обернуть его. - person mohammad rostami siahgeli   schedule 13.12.2019