LINQ多对多的Left Join Grouping

时间:2009-08-20 16:25:29

标签: c# linq

我有很多表关系:

CUS_Phone :拥有自己的唯一ID,来自其父表的cus id以及名称标题日期等... CUS_Phone_JCT :拥有自己唯一的ID,来自CUS_Phone的ID和来自CUS_Phone的ID CUS_Phone :拥有自己唯一的ID和电话号码

这里我有一个连接查询来检索所有客户名称和电话号码:

var q = from c in CUS_Contact
    join cp in CUS_Phone_JCT on c.Id equals cp.Contact_Id into cp2 
    from cp3 in cp2.DefaultIfEmpty()
    join p in CUS_Phone on cp3.Phone_Id equals p.Id into p2 
    from p3 in p2.DefaultIfEmpty()
    where c.Cus_Id == 9120
    select new
            {
                c.Id,
                c.Cus_Id, 
                c.Namefirst, 
                c.Namemiddle, 
                c.Namelast, 
                cp3.Phone.Phone, 
                c.Title, 
                c.Dept, 
                c.Des, c.Datecreate, 
                c.Dateupdate, 
                c.Usr_idcreate, 
                c.Usr_idupdate
            };

foreach(var v in q){
Console.WriteLine(v.Id + "-" + v.Namefirst + "-" + v.Phone);
}

如何制定查询以对每位客户的数字进行分组?我希望看到不同的客户,每个客户都有一个数字列表(IEnumerable List)。这是LINQPad spanishOrders查询中的类似示例,但它们按订单分组订单详细信息。我不知道如何使用我的架构执行此操作。谢谢!


编辑:这是从第一个答案中输出的sql ...

-- Region Parameters
DECLARE @p0 Int SET @p0 = 4
-- EndRegion
SELECT (
    SELECT [t8].[id]
    FROM (
        SELECT TOP (1) [t6].[id]
        FROM [CUS_Contact] AS [t6]
        LEFT OUTER JOIN [CUS_Phone_JCT] AS [t7] ON [t6].[id] = [t7].[Contact_Id]
        WHERE [t2].[id] = [t6].[id]
        ) AS [t8]
    ) AS [Id], (
    SELECT [t11].[Cus_Id]
    FROM (
        SELECT TOP (1) [t9].[Cus_Id]
        FROM [CUS_Contact] AS [t9]
        LEFT OUTER JOIN [CUS_Phone_JCT] AS [t10] ON [t9].[id] = [t10].[Contact_Id]
        WHERE [t2].[id] = [t9].[id]
        ) AS [t11]
    ) AS [Cus_Id], (
    SELECT [t14].[namefirst]
    FROM (
        SELECT TOP (1) [t12].[namefirst]
        FROM [CUS_Contact] AS [t12]
        LEFT OUTER JOIN [CUS_Phone_JCT] AS [t13] ON [t12].[id] = [t13].[Contact_Id]
        WHERE [t2].[id] = [t12].[id]
        ) AS [t14]
    ) AS [Namefirst], (
    SELECT [t17].[namemiddle]
    FROM (
        SELECT TOP (1) [t15].[namemiddle]
        FROM [CUS_Contact] AS [t15]
        LEFT OUTER JOIN [CUS_Phone_JCT] AS [t16] ON [t15].[id] = [t16].[Contact_Id]
        WHERE [t2].[id] = [t15].[id]
        ) AS [t17]
    ) AS [Namemiddle], (
    SELECT [t20].[namelast]
    FROM (
        SELECT TOP (1) [t18].[namelast]
        FROM [CUS_Contact] AS [t18]
        LEFT OUTER JOIN [CUS_Phone_JCT] AS [t19] ON [t18].[id] = [t19].[Contact_Id]
        WHERE [t2].[id] = [t18].[id]
        ) AS [t20]
    ) AS [Namelast], (
    SELECT [t23].[title]
    FROM (
        SELECT TOP (1) [t21].[title]
        FROM [CUS_Contact] AS [t21]
        LEFT OUTER JOIN [CUS_Phone_JCT] AS [t22] ON [t21].[id] = [t22].[Contact_Id]
        WHERE [t2].[id] = [t21].[id]
        ) AS [t23]
    ) AS [Title], (
    SELECT [t26].[dept]
    FROM (
        SELECT TOP (1) [t24].[dept]
        FROM [CUS_Contact] AS [t24]
        LEFT OUTER JOIN [CUS_Phone_JCT] AS [t25] ON [t24].[id] = [t25].[Contact_Id]
        WHERE [t2].[id] = [t24].[id]
        ) AS [t26]
    ) AS [Dept], (
    SELECT [t29].[des]
    FROM (
        SELECT TOP (1) [t27].[des]
        FROM [CUS_Contact] AS [t27]
        LEFT OUTER JOIN [CUS_Phone_JCT] AS [t28] ON [t27].[id] = [t28].[Contact_Id]
        WHERE [t2].[id] = [t27].[id]
        ) AS [t29]
    ) AS [Des], (
    SELECT [t32].[datecreate]
    FROM (
        SELECT TOP (1) [t30].[datecreate]
        FROM [CUS_Contact] AS [t30]
        LEFT OUTER JOIN [CUS_Phone_JCT] AS [t31] ON [t30].[id] = [t31].[Contact_Id]
        WHERE [t2].[id] = [t30].[id]
        ) AS [t32]
    ) AS [Datecreate], (
    SELECT [t35].[dateupdate]
    FROM (
        SELECT TOP (1) [t33].[dateupdate]
        FROM [CUS_Contact] AS [t33]
        LEFT OUTER JOIN [CUS_Phone_JCT] AS [t34] ON [t33].[id] = [t34].[Contact_Id]
        WHERE [t2].[id] = [t33].[id]
        ) AS [t35]
    ) AS [Dateupdate], (
    SELECT [t38].[usr_idcreate]
    FROM (
        SELECT TOP (1) [t36].[usr_idcreate]
        FROM [CUS_Contact] AS [t36]
        LEFT OUTER JOIN [CUS_Phone_JCT] AS [t37] ON [t36].[id] = [t37].[Contact_Id]
        WHERE [t2].[id] = [t36].[id]
        ) AS [t38]
    ) AS [Usr_idcreate], (
    SELECT [t41].[usr_idupdate]
    FROM (
        SELECT TOP (1) [t39].[usr_idupdate]
        FROM [CUS_Contact] AS [t39]
        LEFT OUTER JOIN [CUS_Phone_JCT] AS [t40] ON [t39].[id] = [t40].[Contact_Id]
        WHERE [t2].[id] = [t39].[id]
        ) AS [t41]
    ) AS [Usr_idupdate], [t2].[id] AS [id2]
FROM (
    SELECT [t0].[id]
    FROM [CUS_Contact] AS [t0]
    LEFT OUTER JOIN [CUS_Phone_JCT] AS [t1] ON [t0].[id] = [t1].[Contact_Id]
    GROUP BY [t0].[id]
    ) AS [t2]
WHERE ((
    SELECT [t5].[Cus_Id]
    FROM (
        SELECT TOP (1) [t3].[Cus_Id]
        FROM [CUS_Contact] AS [t3]
        LEFT OUTER JOIN [CUS_Phone_JCT] AS [t4] ON [t3].[id] = [t4].[Contact_Id]
        WHERE [t2].[id] = [t3].[id]
        ) AS [t5]
    )) = @p0
GO

-- Region Parameters
DECLARE @x1 Int SET @x1 = 9327
-- EndRegion
SELECT [t2].[phone] AS [value]
FROM [CUS_Contact] AS [t0]
LEFT OUTER JOIN [CUS_Phone_JCT] AS [t1] ON [t0].[id] = [t1].[Contact_Id]
LEFT OUTER JOIN [CUS_Phone] AS [t2] ON [t2].[id] = [t1].[Phone_Id]
WHERE @x1 = [t0].[id]
GO
-- Region Parameters
DECLARE @x1 Int SET @x1 = 9328
-- EndRegion
SELECT [t2].[phone] AS [value]
FROM [CUS_Contact] AS [t0]
LEFT OUTER JOIN [CUS_Phone_JCT] AS [t1] ON [t0].[id] = [t1].[Contact_Id]
LEFT OUTER JOIN [CUS_Phone] AS [t2] ON [t2].[id] = [t1].[Phone_Id]
WHERE @x1 = [t0].[id]

1 个答案:

答案 0 :(得分:3)

除了cp3.Phone.Phonejoin之外,我对你使用CUS_Phone感到有点困惑,所以我假设前者意味着你不需要后者。否则,只需在p3中为cp3切换join,然后相应地调整g.Select()

那就是说,你应该能够简单地分组联系人ID:

var q = from c in CUS_Contact
        join cp in CUS_Phone_JCT on c.Id equals cp.Contact_Id into cp2 
        from cp3 in cp2.DefaultIfEmpty()
        group new { c, cp3.Phone.Phone } by c.Id into g
        let c = g.First().c
        select new {
                       c.Id,
                       c.Cus_Id, 
                       c.Namefirst, 
                       c.Namemiddle, 
                       c.Namelast, 
                       Phones = g.Select(x => x.Phone)
                       c.Title, 
                       c.Dept, 
                       c.Des, c.Datecreate, 
                       c.Dateupdate, 
                       c.Usr_idcreate, 
                       c.Usr_idupdate
                   };

foreach(var v in q) {
    Console.WriteLine(v.Id + "-" + v.Namefirst);
    foreach(var p in v.Phones) {
        Console.WriteLine(" -" + p);
    }
}

在黑暗中拍几张以提高性能:

var q = from c in CUS_Contact
        join cp in CUS_Phone_JCT on c.Id equals cp.Contact_Id into cp2 
        from cp3 in cp2.DefaultIfEmpty()
        group new { c, cp3.Phone.Phone } by c.Id into g
        let c = g.First().c
        select new {
                       c.Id,
                       c.Cus_Id, 
                       c.Namefirst, 
                       c.Namemiddle, 
                       c.Namelast, 
                       Phones = g.Select(x => x.Phone)
                       c.Title, 
                       c.Dept, 
                       c.Des, c.Datecreate, 
                       c.Dateupdate, 
                       c.Usr_idcreate, 
                       c.Usr_idupdate
                   };

您也可以尝试按复合键(包含所有c字段)而不是c.Id进行分组:

        group cp3.Phone.Phone
          by new { c.Id, c.Cus_Id, c.Namefirst, ETC } into g
        let c = g.Key
        select new {
                       ...
                       Phones = g.Select(p => p),
                       ...
                   }

更新:调整复合键示例以仅对Phone值进行分组,因为您需要的其他所有内容都应该在键中。


更新2:您可以通过嵌入子查询来简化相当多的事情:

var q = from c in CUS_Contact
        select new {
                       c.Id,
                       c.Cus_Id, 
                       c.Namefirst, 
                       c.Namemiddle, 
                       c.Namelast, 
                       Phones = (from cp in CUS_Phone_JCT
                                 where c.Id == cp.Contact_Id
                                 select cp.Phone.Phone),
                       c.Title, 
                       c.Dept, 
                       c.Des, c.Datecreate, 
                       c.Dateupdate, 
                       c.Usr_idcreate, 
                       c.Usr_idupdate
                   };