views:

4155

answers:

4

Assuming a table of tags like the stackoverflow question tags:

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

What is the most efficient way to get the 25 most used tags using LINQ? In SQL, a simple GROUP BY will do:

SELECT Tag, COUNT(Tag) FROM Tags GROUP BY Tag

I've written some LINQ that works:

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);

Like, really? Isn't this mega-verbose? The sad thing is that I'm doing this to save a massive number of queries, as my Tag objects already contain a Frequency property that would otherwise need to check back with the database for every Tag if I actually used the property.

So I then parse these anonymous types back into Tag objects:

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

I'm a LINQ newbie, and this doesn't seem right. Please show me how it's really done.

+4  A: 

I'm pretty sure you've got it right. And, the SQL that LINQ generates and will send to your db will look just like the SQL you started with, so while you're doing a bit more typing, your database isn't doing any more work.

James Curran
+4  A: 

If you want Tag objects, why not create them directly from your Linq query?

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);
GalacticCowboy
Aha! That's what I was missing, thanks!
tags2k
Further to this, I got an "explicit construction of entity type in query is not allowed" error. Seems you can't!
tags2k
I suspect it's because Tag is a data context type - you can definitely do this with other types, but Linq is apparently trying to protect you from creating Tag instances that don't correspond to data context items.
GalacticCowboy
+3  A: 

If you use the verbose form of the syntax, your code will be verbose. Here's an alternative:

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();
David B
There, corrected my many errors. I'm done editting, lol
David B
A: 

I think you are also be unfair in that your SQL query does not do the same thing as your LINQ query - it doesn't return the top 25.

NetMage