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

标签 linq linq-to-sql linq-to-objects self-join

有人能帮忙吗?

我有 1 个类,基本上它包含成员,在该类中是一个列表。

我在列表中的成员也...所以基本上是这样的,

我有 2 个成员,每个成员都有多个 session 。

我希望只返回每个成员 1 个 session 。

我做了一个LINQ查询,当然不行...

我想我需要做一个 self 加入,有什么想法吗?

基本上我的错误是我的子查询自连接中不存在 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 条记录,但我可以访问所有属性...

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

谢谢。

最佳答案

除非我遗漏了什么你需要这个,不是吗?

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

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

编辑: 您使用的 let 选项没问题,请记住,如果成员的 session 列表为空,FirstOrDefault 将返回 null,然后 sn.SessionEndTime 命中 null 引用。另一方面,如果您确定每个成员至少有一个 session ,请改用 First 或聚合。 也不要在 let 中使用 FirstOrDefault(),它会弄乱 LINQ 并阻止它把它绑定(bind)到 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};

至于ordering vs 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]

在 SessioEndTime 上使用降序索引,排序脚本大约慢两倍(您可以获取这些执行计划以自行检查),没有索引它大约慢 5 倍。

关于LINQ: 自连接查询,如何实现?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5026970/

相关文章:

c# - 如何在C#中将Linq Select Enumerable转换为首选类型?

vb.net - linq中的后期绑定(bind)

asp.net - 更新 .dbml 文件

c# - 使用 LINQ to SQL 对所有内容进行分组、求和和聚合

c# - Linq Left Outer Join With latest datetime 在右侧

c# - 我怎样才能使用 linq2sql 来做到这一点...?

c# - Linq 内部的 Linq 导致序列不返回任何结果

c# - 如何将这些 C# foreach 循环转换为 LINQ to Objects 并返回 bool 值?

c# - 如何按 double 值对 List<T> 进行排序?

c# - DistinctBy 在 C#/Visual Studio 2012 中不起作用