Npgsql — EF6: вложенный FirstOrDefault() в подзапросе свойства навигации выдает «Не реализованное» исключение

#entity-framework #npgsql #entity-framework-6.1

#entity-framework #npgsql #entity-framework-6.1

Вопрос:

Структура является базовой. У меня есть родительский элемент «App», у которого много дочерних элементов «PositionData». Я хочу получить некоторые базовые данные для «приложения» вместе с последними «PositionData» этого приложения в одном запросе.

Запрос

             var data = context.Apps.Where(a => a.Id == appId).
            Select(c => new {
                DeviceInfo=c.Device,
                LastPosition=c.PositionData.OrderByDescending(p=>p.DateCreated).FirstOrDefault() 
            }).SingleOrDefault();
 

Выполнение следующей команды выдает «System.NotImplementedException»

Чтобы убедиться, что исключение выдается только в случае подзапроса, я разбил это на 2 запроса, и он отлично работает.

             var tempObj = context.Apps.Where(a => a.Id == appId).SingleOrDefault();
            var data=new {
                DeviceInfo=tempObj.Device,
                LastPosition=tempObj.PositionData.OrderByDescending(p=>p.DateCreated)).FirstOrDefault() 
            };
 

Я искал много дней, также посещал форумы pg foundry, но решения пока нет.

Ответ №1:

Прежде всего, я должен сказать, что я действительно не эксперт по postgresql. Эта проблема определенно является ошибкой или, по крайней мере, функциональным ограничением поставщика npgsql. С поставщиком Sql-сервера этот оператор работает так, как ожидалось, хотя он создает действительно уродливый и медленный оператор TSql.

  var data = context.Apps.Where(a => a.Id == appId).
            Select(c => new {
                DeviceInfo=c.Device,
                LastPosition=c.PositionData.OrderByDescending(p=>p.DateCreated).FirstOrDefault() 
            }).SingleOrDefault();
 

Следующее утверждение, очевидно, намного больше вашего, но, хотите верьте, хотите нет, оператор Store намного меньше и лучше оптимизирован. Результат должен быть таким же, если вы убедитесь, что комбинация AppID и DateCreated в таблице PositionData уникальна.

 var data = from a in context.Apps
           join pd in context.PositionData.GroupBy(p => p.AppId)
               .Select(p => new { AppId = p.Key, Date = p.Max(x => x.DateCreated) })
               on a.Id equals pd.AppId into pdgrp
           from lpd in pdgrp.DefaultIfEmpty()
           join p in context.PositionData on lpd equals new { AppId = p.AppId, Date = p.DateCreated } into pgrp
           from lp in pgrp.DefaultIfEmpty()
           where a.Id == appId
           select new {
               DeviceInfo = a.Device,
               LastPosition = lp
           };
 

Возможно, это утверждение также переводится на Postresql

Обновление: некоторые показатели производительности.

Я тестировал на локальном SQL 2012 с действительно быстрыми твердотельными накопителями. Для первой версии поставщик SQL Server создает ВНЕШНЮЮ инструкцию APPLY для второго с двумя ЛЕВЫМИ ВНЕШНИМИ СОЕДИНЕНИЯМИ. Тестовые данные составляли 15 000 приложений и 150 000 записей PositionData.

                  join                      outer apply  
                 reads     duration        reads    duration
all rows          1528          519       444434         912
single row          68            0           35           0
 

после добавления требуемого уникального индекса (AppID ASC, DateCreated DESC)

 all rows           884          220        49875         180
single row          28            0           15           0
 

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

1. Он может быстрее и меньше транслироваться в TSQL, но как насчет чистой производительности выполнения SQL?

2. Ну, это зависит от того, сколько строк у вас есть в ваших таблицах и сколько вы хотите выбрать. Я обновил свой ответ значениями производительности… но имейте в виду. Эти значения взяты из локального sql 2012, работающего на очень быстром SSD. В другой системе чтения оказывают гораздо большее влияние, чем в моей системе.

Ответ №2:

Я открыл проблему в репозитории Npgsql Git Hub. И казалось, что эта ошибка действительно была вызвана не реализованной функцией Npgsql.

Теперь они внедрили эту функцию и объединили ее с основной веткой. Загрузка Npgsql и NpgsqlEntityFramework .версии dll> = 2.2 устранят проблему. ХОТЯ в этом исправлении используется «боковое» ключевое слово sql, которое было введено в PostgreSQL версии 9.3, так что версия Postgresql также необходима.