2012-02-19 2 views
0

(ParentID) :정렬 오브젝트 나는이 필드 개체의 컬렉션을 가지고

MessageID int, 
Text string, 
ParentMessageID int? 

일부 예제 데이터 :

1 | "Text 1" | null 
2 | "Reply to Text 1" | 1 
3 | "Reply to Text 1 #2" | 1 
4 | "Reply to reply to text 1" | 2 

내가 부모와 자식 메시지로이 컬렉션을 정렬 할 ID는 다음과 같이 정렬됩니다.

1 
2 
4 (child of 2) 
3 

LINQ로 수행하는 방법은 무엇입니까?

var q = from i in _dbContext.Messages where ... orderby ... 
먼저 루트에 전체 경로를 포함하는 각 행에 대해 방법이 필요
+1

:

WITH Hierarchy AS ( SELECT ID, ParentID = CAST(ParentID AS INT), MsgText, NodePath = CAST('/' + CAST(ID AS VARCHAR(5)) AS VARCHAR(MAX)) FROM dbo.MessageTest WHERE ParentID IS NULL UNION ALL SELECT m.ID, m.ParentID, m.MsgText, CAST(h.NodePath + '/' + CAST(m.ID AS VARCHAR(5)) AS VARCHAR(MAX)) FROM dbo.MessageTest m INNER JOIN Hierarchy h ON m.ParentID = h.ID ) SELECT * FROM Hierarchy ORDER BY NodePath 

이 나에게의 출력을 제공? 왜 4가 3보다 먼저 나오나요? – BrokenGlass

+0

정렬은 메시지에 대한 답장이됩니다 (ParentMessageID를보십시오) – John

+0

답글 수를 기준으로 정렬 하시겠습니까? 아직도 이것은 3이 3보다 먼저 올 이유를 말해주지 않습니다. – BrokenGlass

답변

1

:

1 | "Text 1" | "1" 
2 | "Reply to Text 1" | "1_2" 
3 | "Reply to Text 1 #2" | "1_3" 
4 | "Reply to reply to text 1" | "1_2_4" 

어느 쪽이든 당신은 귀하의 의견을 저장하거나에 즉시 그것을 계산할 때 직접 저장 코드 (다소 비싸다). 그런 다음이 열을 기준으로 정렬하는 간단한 문제입니다 (텍스트로 생각하십시오).

+2

매우 비쌉니다. 우리가 작업 한 프로젝트에서 이처럼 계산/정렬하려고하는 매우 저조한 퍼포먼스를 보았습니다. 정렬 키를 미리 계산하는 것이 훨씬 빠릅니다. –

0

먼저 트리를 만든 다음 루트에서 리프로 재귀 적으로 내려갑니다. 이 작업을 수행하는 방법에는 여러 가지가 여기에 하나가 있습니다 :

class Message { 

    public Message(int message_id, string text, int? parent_message_id) { 
     Debug.Assert(message_id < int.MaxValue); 
     MessageID = message_id; 
     ParentMessageID = parent_message_id; 
     Text = text; 
    } 

    public readonly int MessageID; 
    public readonly string Text; 
    public readonly int? ParentMessageID; 

    public static IEnumerable<Message> OrderByHierarchy(IEnumerable<Message> messages) { 

     // Key: ParentMessageID (null substituted with int.MaxValue). 
     // Value: All messages sharing this parent. 
     var dict = messages.GroupBy(m => m.ParentMessageID ?? int.MaxValue).ToDictionary(grouping => grouping.Key); 

     // For each root, recursively traverse its children. 
     return dict[int.MaxValue].SelectMany(root => RecursiveDescent(dict, root)); 

    } 

    static IEnumerable<Message> RecursiveDescent(Dictionary<int, IGrouping<int, Message>> dict, Message parent) { 

     yield return parent; 

     IGrouping<int, Message> children; 
     if (dict.TryGetValue(parent.MessageID, out children)) 
      foreach (var child in children) 
       foreach (var descendent in RecursiveDescent(dict, child)) 
        yield return descendent; 

    } 

    public override string ToString() { 
     return string.Format("{0} | {1} | {2}", MessageID, Text, ParentMessageID == null ? "null" : Convert.ToString(ParentMessageID)); 
    } 

} 

class Program { 

    static void Main(string[] args) { 

     var messages = new[] { 
      new Message(1, "Text 1", null), 
      new Message(2, "Reply to Text 1", 1), 
      new Message(3, "Reply to Text 1 #2", 1), 
      new Message(4, "Reply to reply to text 1", 2), 
     }; 

     foreach (var m in Message.OrderByHierarchy(messages)) 
      Console.WriteLine(m); 

    } 

} 

이 인쇄 :와

1 | Text 1 | null 
2 | Reply to Text 1 | 1 
4 | Reply to reply to text 1 | 2 
3 | Reply to Text 1 #2 | 1 
0

은 CTE SQL Server의 (공통 테이블 식), 당신은 당신이 찾고있는 무엇을 달성 할 수 - 그러면 당신은 이것을 "지속"시킬 수 있습니다. 보기 및 Linq-to-SQL 코드에서 볼 수있는 쿼리. 당신이 정확히 무엇을하여 정렬 할

ID ParentID MsgText     NodePath 
1 NULL  Text 1 1   /1 
2 1   Reply to Text #1  /1/2 
4 2   Reply to text #2  /1/2/4 
3 1   Reply #2 to Text #1  /1/3