Question

Working with Entity Framework in ASP.Net MVC 4, and need to use linq to output a line of information.

I have an ArticleView table and an Article table. I need to output an article with the most activity within a 24 hour period.

Here's my ArticleView table:

int ArticleID
DateTime ViewCreated

Article table:

int ID
string title

Sample Data:

ArticleView:
ArticleID   ViewCreated
   2          4/8/2014 1:48:40 PM
   2          4/8/2014 1:50:40 PM
   2          4/8/2014 1:55:20 PM
   3          4/8/2014 12:07:30 PM

Note: ViewCreated is automatically generated once someone views an article.

Article:
    ID       Title
    2        Article2
    3        Article3

Expected Output:

Article with the most activity within 24 hours is:

Article2(3)

What I have to work with:

var articles = db.Articles;
var articleviews = db.ArticleViews;

Just not sure how to approach this.

Was it helpful?

Solution

Something like this:

var viewsById = db.ArticleViews
    .Where(av => av.ViewCreated >= startDateTime && av.ViewCreated < endDateTime)
    .GroupBy(av => av.ArticleId)
    .Select(g => new { ArticleId = g.Key, Count = g.Count() })

var highestCount = viewsById.Max(v => v.Count);

var topArticles = viewsById.Where(a => a.Count == highestCount);

var topArticle = topArticles.First();

var message = String.Format("Article id: {0}, views: {1}", 
                         topArticle.ArticleId, topArticle.Count);
  1. Filter the views to be within the specified date range.
  2. Group them by article Id.
  3. Make an anonymous object of each one, storing the article Id and the count of views for that article.
  4. Take the one with the highest count.

OTHER TIPS

You can do this is one statement by using a join:

var mostViewedArticleTitleAndCount = db.Articles
     .Join(ArticleViews.Where (av => av.ViewCreated > sinceDate),
        a => a.ID,
        v => v.ArticleID,
        (a,v) => new { a,v })
    .GroupBy (g => g.a.ID)
    .Select (g => new { g.Key, Title = g.First ().a.Title, Count = g.Count ()})
    .OrderByDescending (g => g.Count)
    .Select (g => g.Title + "(" + g.Count + ")")
    .First ();

For your test data this will output:

Article2(3)

To get the article you can simply do this:

var article = db.Articles.OrderByDescending(a=>a.ArticleViews.Count())
              .Take(1).FirstOrDefault();

Or

var article = db.Articles.OrderByDescending(a=>a.ArticleViews.Count())
              .FirstOrDefault()//this should work too

One shorter way of a suggested solution here is:

var mostViewedArticle = db.ArticleViews
    .Where(av => av.ViewCreated >= startDateTime && av.ViewCreated < endDateTime)
    .GroupBy(av => av.ArticleId)
    .OrderByDescending(g=> g.Count())
    .Select(g => g.First().Article)
    .Take(1)
  1. Filtering by some date range
  2. Grouping by ArticleId
  3. Ordering by with the most count on top
  4. Selecting the Article through navigation property
  5. Taking only the First one.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top