2 回答
TA贡献1794条经验 获得超7个赞
等效的 LINQ to Entities 查询,它密切转换为您所追求的 SQL 查询,如下所示:
var roomIds = plan.Rooms.Select(rm => rm.Id);
var query =
from rm in context.Rooms
join conf in context.Conferences on rm.Id equals conf.RoomId
into rmConf from rm in rmConf.DefaultIfEmpty() // left join
where roomIds.Contains(rm.Id)
group conf by rm.Id into g
select new
{
RoomId = g.Key,
LastUsedDate = g.Max(conf => (DateTime?)conf.EndTime)
};
诀窍是从 EF 开始查询IQueryable,从而允许它完全转换为 SQL,而不是从plan.Rooms有问题的查询中开始,这IEnumerable使得整个查询在内存中执行(context.Conferences被视为IEnumerable并导致将整个表加载到记忆)。
SQLIN子句是通过in memoryIEnumerable<Guid>和Containsmethod实现的。
最后,无需检查计数。SQL 自然会处理nulls,您只需要确保调用可为空的Max重载,这是通过强制转换实现的(DateTime?)conf.EndTime。不需要像在 LINQ to Objects 中那样检查conf,null因为 LINQ to Entities/SQL 自然也会处理(只要接收器变量可以为空)。
TA贡献1799条经验 获得超9个赞
由于plan.Rooms没有IQueryable附加查询提供程序,连接语句被编译为Enumarable.Join. 这意味着在其他运算符应用于它之前,它context.Conferences被隐式转换为IEumerable并且其内容被拉入内存。
您可以通过不使用来解决此问题join:
var roomIds = plan.Rooms.Select(r => r.Id).ToList();
var maxPerRoom = context.Conferences
.Where(conf => roomIds.Contains(conf.RoomId))
.GroupBy(conf => conf.RoomId)
.Select(g => new
{
RoomId = g.Key,
LastUsedDate = g.Select(conf => conf.EndTime)
.DefaultIfEmpty()
.Max()
}
).ToList();
var roomData = (
from rm in plan.Rooms
join mx in maxPerRoom on rm.Id equals mx.RoomId
select new
{
RoomId = rm.Id,
LastUsedDate = mx.LastUsedDate
}
).ToList();
第一步LastUsedDate从上下文收集数据,然后与plan.Rooms内存中的集合连接。如果您对返回/显示房间 ID 以外的任何其他内容不感兴趣,则甚至不需要最后一步,但这取决于您。
- 2 回答
- 0 关注
- 306 浏览
添加回答
举报