如何完成LINQ自连接查询

问题描述 投票:0回答:1

members
拥有成员,并且该类中有一个
List<Sessions>
。我也有
List
的成员。

我有 2 名成员,每个成员都有多个会话。我希望每个会员只返回 1 个会话。

为什么我的 LINQ 查询会出现错误:子查询自连接中不存在

m

var sessions =  
from m in this.members                     
join s in
(
    from se in m.Sessions
    group se by se.Name into g
    select new {Name = g.Key, SessioEndTime = g.Max(a=>a.SessioEndTime)}
)   
on m.Name equals s.Name                    
select new { MemberName = m.Name, SessionTime = s.SessioEndTime}

我设法用以下方法做到了,但这是最好的方法吗?

var sessions =  
from m in this.members                     
let sn = m.Sessions.OrderByDescending(a => a.SessionEndTime).FirstOrDefault()                
select new { MemberName = m.Name, SessionTime = sn.SessioEndTime}

sn
包含 1 条记录,但我可以访问所有属性。

linq linq-to-sql linq-to-objects self-join
1个回答
5
投票

你需要

var sessions = 
   from m in members
   select new { 
      MemberName = m.Name, 
      SessionTime = m.Sessions.Max(s => s.SessioEndTime)
   };

您必须改变对 LINQ 查询的看法。更多地从对象的角度思考,而不是从 SQL 实现的角度思考。 “我需要什么?我需要所有成员,每个成员都有其最新的会话结束时间。”然后采取行动。

你使用的let选项是可以的;请记住,如果 member 具有空的会话列表,则 FirstOrDefault 将返回 null,然后 sn.SessionEndTime 命中 null 引用。另一方面,如果您确定每个成员至少有一个会话,请使用 First 代替或聚合。

不要在let中使用FirstOrDefault()。它会扰乱 LINQ 并阻止其将其绑定到主服务器(导致每个主服务器都有一个单独的 SQL 查询来检测丢失的子集)。因此,可用的 let 查询是:

from m in Members                     
let sn = m.Sessions.Max(s => s.SessioEndTime)                
select new { MemberName = m.Name, SessionTime = sn};

from m in Members                     
let sn = m.Sessions.OrderByDescending(a => a.SessioEndTime).First()              
select new { MemberName = m.Name, SessionTime = sn.SessioEndTime};

对于排序与最大聚合,两个查询都会生成子查询:

-- MAX    
SELECT [t0].[Name] AS [MemberName], (
    SELECT MAX([t1].[SessioEndTime])
    FROM [Session] AS [t1]
    WHERE [t1].[memberId] = [t0].[id]
    ) AS [SessionTime]
FROM [Member] AS [t0]
GO

-- ordering
SELECT [t0].[Name] AS [MemberName], (
    SELECT [t2].[SessioEndTime]
    FROM (
        SELECT TOP (1) [t1].[SessioEndTime]
        FROM [Session] AS [t1]
        WHERE [t1].[memberId] = [t0].[id]
        ORDER BY [t1].[SessioEndTime] DESC
        ) AS [t2]
    ) AS [SessionTime]
FROM [Member] AS [t0]

使用 SessioEndTime 的降序索引,排序脚本大约慢两倍(您可以获取这些执行计划来自行检查)。如果没有索引,速度大约慢五倍。

© www.soinside.com 2019 - 2024. All rights reserved.