结构是基本的。我有一个“App”父母,有很多“PositionData”孩子。 我想在单个查询中检索“App”的一些基本数据以及该App的Last“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代工厂论坛但还没有解决方案。
答案 0 :(得分:1)
首先我要说,我真的没有postgresql专家。这个问题肯定是一个bug或至少是npgsql提供程序的功能限制。使用Sql Servier提供程序,此语句按预期工作,但它会创建一个非常丑陋且缓慢的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语句更小,更优化。只要您确保PositionData表中的AppId和DateCreated组合是唯一的,结果应该是相同的。
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
更新:一些绩效指标。
我已经使用非常快的ssds在本地SQL 2012上进行了测试。对于第一个版本,SQL Server提供程序为第二个LEFT OUTER JOINS创建一个OUTER APPLY语句。 TestData是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 :(得分:0)
我已在Npgsql Git Hub存储库中打开了该问题。并且看起来这个错误确实是由未实现的Npgsql功能引起的。
他们现在已经实现了该功能并将其合并到主分支。 下载Npgsql和NpgsqlEntityFramework .dll版本> = 2.2将解决此问题。 虽然这个修复程序使用" Lateral"在PostgreSQL v9.3中引入了sql关键字,因此也需要Postgresql版本。