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

?为什么4在3之前? – BrokenGlass 2012-02-19 16:44:20

+0

排序是对邮件的回复(看ParentMessageID) – John 2012-02-19 16:48:52

+0

按回复计数排序?但这并不能告诉我为什么4会在3 – BrokenGlass 2012-02-19 16:49:48

回答

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

绝对是非常昂贵的。在我工作的一个项目上,我们看到了非常糟糕的表现,试图在飞行中像这样计算/排序。预先计算排序关键要快得多。 – 2012-02-19 17:39:32

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代码查询该视图。

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 

这让我的输出:你想究竟对它进行排序

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