2009-08-20 79 views
1

我有一个多对多的关系表船:LINQ多对多左连接分组

CUS_Phone:拥有自己唯一的ID,从它的父表CUS ID以及姓名职务日期等。 .. CUS_Phone_JCT:拥有自己的唯一ID,从CUS_Phone ID和从CUS_Phone CUS_Phone的ID:拥有自己独特的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)。 Theres在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] 

回答

3

我有点贵,除了使用cp3.Phone.Phone迷惑你joinCUS_Phone,所以我假设前者意味着你不需要后者。否则,只需在join中切入p3,cp3并相应地调整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), 
         ... 
        } 

更新:调整了复合键示例只分组电话值,因为你需要的一切都应该在关键。


更新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 
        }; 
+0

林不知道有关Phone.Phone无论是。它会输出表名“CUS_Phone”,除非我添加第二个。查询的效果很好,除了需要几乎4秒的时间,与以前相比,只需要不到十分之一秒。有任何想法吗? – RyanOC 2009-08-20 17:16:10

+0

生成的SQL看起来像什么? – dahlbyk 2009-08-20 17:44:03

+0

它太大,无法进入这里。 600个字符的限制和约4000. – RyanOC 2009-08-20 18:11:47