2011-06-06 45 views
0

我有一個內存List<TreeNode>。是否有可能使用linq來選擇所有葉節點?Linq左外連接到同一個列表上找到葉節點

的SQL會是這個樣子:

SELECT  
    t1.Name 
FROM 
    Tree t1 
    LEFT JOIN Tree t2 
     ON t1.UserId = t2.ParentId 
WHERE 
    t2.UserId is null 

,我已經得到的最接近的(我還需要篩選出空值):

     var test = from t1 in list 
         join t2 in list 
         on t1.UserId equals t2.ParentId into g     

         from result in g.DefaultIfEmpty()   

         select new { 
         t1.Name 
         }; 

將會產生正確的SQL (當在linqpad中測試時)沒有where子句。如果我嘗試在t2 == null的地方過濾結果,我無法訪問t2選擇匿名對象的地方。我是否需要創建列表的副本並加入到該列表中?

回答

2

編輯:好的,我之前被誤解了。所以你基本上是在項目後面(t1)列表裏沒有元素t2這樣的t1.UserId == t2.ParentId?在這種情況下,我建議你使用:

我懷疑你想:我不是在這裏使用匿名類型你只選擇單個值

var test = from t1 in list 
      join t2 in list 
       on t1.UserId equals t2.ParentId into g 
      where !g.Any() 
      select t1.Name; 

注意。

另一種方法是:

var parents = new HashSet<Guid>(list.Where(x => x.ParentId != null) 
            .Select(x => x.ParentId.Value)); 
var query = list.Where(t1 => !parents.Contains(t1.UserId)); 
+0

應該澄清 - 生產中linqpad – woggles 2011-06-06 12:27:40

+0

這會產生運行查詢時,正確的SQL'選擇[T 0] [名稱] FROM [Tree] AS [t0] LEFT OUTER JOIN [Tree] AS [t1] ON(([t0]。[UserId])= [t1]。[ParentId])AND(0 = 1)' – woggles 2011-06-06 12:37:00

+0

@護目鏡:這似乎很奇怪......但它在你的usi實際場景中有什麼作用將它列入清單?你的情況下'UserId'的類型是什麼? – 2011-06-06 13:22:12

0

試試這個:

var test = from t1 in list 
      join t2 in list 
      on t1.UserId equals t2.ParentId into g     
      from result in g.DefaultIfEmpty()   
      where t2.UserId == null 
      select new { 
       t1.Name 
      }; 
+0

名稱't2'不存在於當前上下文 – woggles 2011-06-06 12:34:00

+0

@ woggles。問題在於,當UserId爲空並且您使用相同的空值應用連接時(null等於t2.ParentId),您需要結果。該空值導致問題。 where子句中不需要空值檢查。它已經由DefaultIfEmpty處理 – 2011-06-06 12:41:37