我有一组包含以下字段的对象:
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 ...
答案 0 :(得分: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"
保存评论时直接保存,或者在代码上动态计算(有点贵)。然后,这个列的排序很简单(正如文字一样)
答案 1 :(得分: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
答案 2 :(得分:0)
使用SQL Server中的CTE(公用表表达式),您可以实现所需的目标 - 然后您可以将其“持久化”到例如一个视图,并从您的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