在LINQ中最流行的GROUP BY是什么?

30
假设有一个与stackoverflow问题标签相关的表格:

TagID(bigint),QuestionID(bigint),Tag(varchar)

使用LINQ获取最常用的25个标签的最有效方法是什么?在SQL中,简单的GROUP BY即可实现:
SELECT Tag, COUNT(Tag) FROM Tags GROUP BY Tag

我已经写了一些有效的LINQ:

var groups = from t in DataContext.Tags
             group t by t.Tag into g
             select new { Tag = g.Key, Frequency = g.Count() };
return groups.OrderByDescending(g => g.Frequency).Take(25);

真的吗?这不是超级冗长吗?可悲的是,我这样做是为了节省大量查询,因为我的标签对象已经包含一个频率属性,否则每个标签都需要与数据库进行检查。

然后,我将这些匿名类型解析回标签对象:

groups.OrderByDescending(g => g.Frequency).Take(25).ToList().ForEach(t => tags.Add(new Tag()
{
    Tag = t.Tag,
    Frequency = t.Frequency
}));

我是一个LINQ新手,这似乎不正确。请向我展示真正的做法。


我认为你的SQL应该是 SELECT Tag, COUNT(Tag) FROM Tags GROUP BY Tag ORDER BY COUNT(Tag) DESC FETCH FIRST 25 ROWS ONLY,这样Linq看起来就不那么糟糕了。 - NetMage
4个回答

25
如果您需要标签对象,为什么不直接从Linq查询中创建它们呢?
var groups = from t in DataContext.Tags
             group t by t.Tag into g
             select new Tag() { Tag = g.Key, Frequency = g.Count() };

return groups.OrderByDescending(g => g.Frequency).Take(25);

除此之外,我遇到了“查询中不允许显式构造实体类型”的错误。看起来你不能这样做! - tags2k
我怀疑这是因为Tag是数据上下文类型 - 您肯定可以使用其他类型来完成此操作,但是Linq显然试图保护您免于创建不对应数据上下文项的Tag实例。 - GalacticCowboy

12

如果您使用语法的详细形式,您的代码将会很冗长。这里有一个替代方案:

List<Tag> result = 
  db.Tags
  .GroupBy(t => t.Tag)
  .Select(g => new {Tag = g.Key, Frequency = g.Count()})
  .OrderByDescending(t => t.Frequency)
  .Take(25)
  .ToList()
  .Select(t => new Tag(){Tag = t.Tag, Frequency = t.Frequency})
  .ToList();

10

我相信你已经做得很正确了。此外,LINQ生成并发送到您的数据库的SQL将看起来与您开始使用的SQL完全相同,因此尽管要多打一些字,但您的数据库不会执行任何额外的工作。


3

我认为你的SQL查询和LINQ查询并不一样 - 它没有返回前25个结果,这是不公平的。


毫无疑问,这是SQL中最难的部分,但完全被忽略了。 - tster

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接