Linq:按子项计数选择父行的最佳方法

时间:2014-01-31 09:03:03

标签: c# linq

我有一个评论表,如下所示:

Comment{  
ID,  
Text,  
ParentID  
}   

我正在使用以下查询根据回复数量选择带有分页的热门评论。

var comments = db.Comments
.OrderByDescending(c => db.Comments.Count(r => r.ParentID == c.ID)).Skip(skip).Take(recordsPerPage).ToList();

当我们收到数以千计的评论时,请告诉我处理这种情况的最佳方法吗?

2 个答案:

答案 0 :(得分:2)

我会考虑在存储回复计数的Comment中添加一个额外的列。然后,您可以通过回复计数轻松订购Comments嵌套查询。

var comments = db.Comments.Skip(skip).Take(recordsPerPage)
                 .OrderByDescending(c => c.ReplyCount)
                 .ToList();

答案 1 :(得分:1)

除非您准备在数据库中预先计算它,否则您遇到的问题是您需要执行嵌套查询或执行单次完全获取,然后执行内存中的所有操作。后者是我的选择,直到它被证明太慢。

以下是我最初的做法。

首先,预取:

var allComments = Comments.ToArray();

然后创建一个快速返回注释计数的函数:

var childrenLookup = allComments.ToLookup(x => x.ParentID);
var parentMap = allComments.ToDictionary(x => x.ID, x => x.ParentID);

Func<int, int> getCommentsCount = n =>
{
    var r = 0;
    if (parentMap.ContainsKey(n))
    {
        r = childrenLookup[parentMap[n]].Count();
    }
    return r;
};

现在返回结果几乎是微不足道的:

var comments = allComments
    .OrderByDescending(c => getCommentsCount(c.ID))
    .Skip(skip)
    .Take(recordsPerPage)
    .ToList();

(并且,是的,您的排序顺序错误,您可以跳过并进行分页。)

如果您不能在内存中执行此操作,请使用预先计算方法。