Мне кажется, я понимаю, что ты пытаешься сделать. Дай мне посмотреть, получу ли я это первым.
С учетом выбранного PostID
вы хотите вернуть все комментарии, чтобы комментарии верхнего уровня (т.е. без родителя) возвращались в порядке создания, а все дочерние комментарии возвращались в порядке создания после каждого родителя и до следующего неродственного родителя. комментарий. Это верно?
Я создал следующий класс и данные испытаний:
public class Comment
{
public int CommentId { get; set; }
public int PostId { get; set; }
public int? ParentId { get; set; }
public string Content { get; set; }
}
var comments = new List<Comment>()
{
new Comment() { PostId = 2, CommentId = 1, },
new Comment() { PostId = 2, CommentId = 2, ParentId = 1, },
new Comment() { PostId = 2, CommentId = 3, },
new Comment() { PostId = 2, CommentId = 4, ParentId = 1, },
new Comment() { PostId = 2, CommentId = 6, ParentId = 5, },
new Comment() { PostId = 2, CommentId = 7, ParentId = 1, },
new Comment() { PostId = 2, CommentId = 8, ParentId = 3, },
// PostId = 3 to test the filter is working
new Comment() { PostId = 3, CommentId = 9, },
// Move this last to test the ordering is working
new Comment() { PostId = 2, CommentId = 5, ParentId = 3, },
};
Я предполагал, что CommentId
будет автоматически увеличиваться, чтобы его можно было использовать для определения порядка создания.
Итак, если я понимаю ваше требование, вы хотите следующий порядок вывода:
id == 1 [pid == ]
id == 2 [pid == 1]
id == 4 [pid == 1]
id == 7 [pid == 1]
id == 3 [pid == ]
id == 5 [pid == 3]
id == 6 [pid == 5]
id == 8 [pid == 3]
Запрос, который должен быть выполнен, таков:
var postId = 2;
var childCommentsLookup =
(from c in comments
where c.PostId == postId
orderby c.CommentId
select c).ToLookup(x => x.ParentId);
Этот запрос не упорядочивает комментарии, но заставляет выполнять один запрос в базе данных и возвращает все комментарии, связанные с postId
.
Теперь вот два способа получить комментарии в правильном порядке.
Во-первых, рекурсивное лямбда-выражение:
//Must declare this as null to allow recursive calling of the lambda.
Action<int?, ILookup<int?, Comment>> output = null;
output = (p, l) =>
{
foreach (var c in l[p])
{
Console.WriteLine("id == {0} [pid == {1}]", c.CommentId, c.ParentId);
output(c.CommentId, l);
}
};
output(null, childCommentsLookup);
Во-вторых, вы можете использовать метод итератора, чтобы просто получить IEnumerable<Comment>
с комментариями в правильном порядке:
public static IEnumerable<Comment> OrderCommentsRecursively(
int? parent, ILookup<int?, Comment> lookup)
{
foreach (var c0 in lookup[parent])
{
yield return c0;
foreach (var c1 in OrderCommentsRecursively(c0.CommentId, lookup))
{
yield return c1;
}
}
}
foreach (var c in OrderCommentsRecursively(null, childCommentsLookup))
{
Console.WriteLine("id == {0} [pid == {1}]", c.CommentId, c.ParentId);
}
Теперь, если вы собираетесь создать функцию итератора, я бы сделал еще один шаг вперед и создал бы хороший метод для непосредственного возврата ваших результатов:
public static IEnumerable<Comment> GetRecursivelyOrderedCommentsByPostId(
IEnumerable<Comment> comments, int postId)
{
return OrderCommentsRecursively(null,
(from c in comments
where c.PostId == postId
select c).ToLookup(x => x.ParentId));
}
foreach (var c in GetRecursivelyOrderedCommentsByPostId(comments, postId))
{
Console.WriteLine("id == {0} [pid == {1}]", c.CommentId, c.ParentId);
}
Результаты этих двух / трех подходов:
Lambda Expression:
id == 1 [pid == ]
id == 2 [pid == 1]
id == 4 [pid == 1]
id == 7 [pid == 1]
id == 3 [pid == ]
id == 5 [pid == 3]
id == 6 [pid == 5]
id == 8 [pid == 3]
Iterator Call:
id == 1 [pid == ]
id == 2 [pid == 1]
id == 4 [pid == 1]
id == 7 [pid == 1]
id == 3 [pid == ]
id == 5 [pid == 3]
id == 6 [pid == 5]
id == 8 [pid == 3]
Query & Iterator Call:
id == 1 [pid == ]
id == 2 [pid == 1]
id == 7 [pid == 1]
id == 4 [pid == 1]
id == 3 [pid == ]
id == 5 [pid == 3]
id == 6 [pid == 5]
id == 8 [pid == 3]
Надеюсь, это поможет.