LINQ:自联接查询,如何实现?

Mar*_*tin 3 linq linq-to-objects self-join linq-to-sql

有人可以帮忙吗?

我有1个类,基本上它拥有成员,并且在该类中是一个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}
Run Code Online (Sandbox Code Playgroud)

我很感激任何人的反馈.

提前致谢.

编辑

好吧,我设法像下面这样做,但这是最好的方法吗?

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

这种方式sn包含1条记录,但我可以访问所有属性...

但这是使用LET的最佳方式吗?

谢谢.

mmi*_*mix 5

除非我遗漏了你需要的东西,不是吗?

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

您必须改变您对LINQ查询的思考方式,从对象点而不是从SQL实现点考虑更多.我需要什么?我需要所有成员,每个成员都有最新的会话结束时间,然后采取行动.

编辑: 你使用的let选项是好的,只要记住一些内容FirstOrDefault将返回null如果成员有一个空的Sessions列表,然后sn.SessionEndTime命中空引用.另一方面,如果您确定每个成员至少使用一个会话First代替或聚合.也不要FirstOrDefault()在let中使用,它会弄乱LINQ并阻止它将它绑定到master(导致每个master的单独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};
Run Code Online (Sandbox Code Playgroud)

对于排序与Max聚合,两个查询都将生成子查询:

-- 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]
Run Code Online (Sandbox Code Playgroud)

使用SessioEndTime上的降序索引,排序脚本大约慢两倍(您可以获得执行计划以自行检查),而索引的速度大约慢5倍.