2012-02-19 36 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

返信件数でソートしますか?それでも私は4が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); 

    } 

} 

これは、出力します。これを行うには多くの方法が一つでここにありますが、SQL ServerのCTE(共通テーブル式)で

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

は、あなたが探しているものを達成できます - あなたはただこれを "持続させる"ことができます。ビュー、およびLinqから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 
関連する問題