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.
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);
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();
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With