#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 также необходима.