Запрос внешнего источника данных с помощью 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.

Тем не менее, может быть, стоит использовать многошаговый подход в качестве компромисса:

  1. Используйте LINQ, чтобы ограничить поиск файлов журналов,
  2. читать файлы и
  3. используйте 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.

Другие вопросы по тегам