Запрос внешнего источника данных с помощью LINQ
Я храню то, что в основном составляет данные журнала, хранящиеся в файлах CSV. Это в формате <datetime>,<val1>,<val2>,
и т. д. Однако файлы журнала хранятся по идентификатору учетной записи и месяцу, поэтому, если вы делаете запрос по месяцам или идентификаторам учетных записей, вы собираетесь получить несколько файлов.
Я хотел бы иметь возможность запросить его с помощью LINQ, так что если бы я мог позвонить logFiles.Where(o => o.Date > 1-1-17 && o.Date < 4-1-17)
, Я предполагаю, что мне нужно что-то, чтобы изучить диапазон дат в этом запросе и заметить, что он охватывает 4 месяца, что затем заставляет его проверять только файлы в этом диапазоне дат.
Есть ли способ сделать это, не связывая мои руки с грязным провайдером IQueryable LINQ? Я могу спуститься в кроличью нору, если это необходимо, но сначала я хочу убедиться, что это правильная кроличья нора.
1 ответ
Если вы хотите фильтровать как по имени файла журнала, так и по содержимому файла журнала в том же Where
выражение, я не вижу решения без кастома IQueryable
Поставщик LINQ, потому что это именно тот случай использования для них: для интеллектуального доступа к данным на основе выражений, используемых в запросе LINQ.
Тем не менее, может быть, стоит использовать многошаговый подход в качестве компромисса:
- Используйте LINQ, чтобы ограничить поиск файлов журналов,
- читать файлы и
- используйте LINQ для дальнейшего поиска.
Пример:
IEnumerable<LogFile> files = LogFiles.Where(f => f.Date > new DateTime(17, 1, 1) && f.AccountID == 4711);
IEnumerable<LogData> data = ParseLogFiles(files);
IEnumerable<LogData> filteredData = data.Where(d => d.val1 == 42 && d.val2 > 17);
LogData firstMatch = filteredData.FirstOrDefault();
Если вы реализуете ParseLogFiles
(а) с отложенным исполнением и (б) в качестве метода расширения на IEnumerable<LogFile>
полученный код будет очень похож на чистый LINQ:
var filteredData = LogFiles.
Where(f => f.Date > new DateTime(17, 1, 1) && f.AccountID = 4711).
ParseLogFiles().
Where(d => d.val == 42 && d.val2 > 17);
// If ParseLogFiles uses deferred execution, the following line won't read
// more log files than required to get the first matching row:
var firstMatch = filteredData.First();
Это немного больше работы, чем иметь все это в одном запросе LINQ, но это избавляет вас от необходимости реализовывать свой собственный поставщик LINQ.