1

I have a table of Widgets with columns "Name" and "Count"

The "Count" field contains count of Posts each Widget would show:

Name        |  Count
---------------------
RecentNews  |    6
SpecialNews |    5
NewsGallery |    10

The second table associated with Widgets Table and Posts Table :

PostID | WidgetID
------------------
100    |    6
101    |    5
102    |    10

For more performance, I just fetch last needed posts for each Widget by this query:

            var postInWidgets = db.PostWidgets
                .GroupBy(pw => pw.WidgetID)
                .SelectMany(g => g.OrderByDescending(p => p.Post.DateCreated).Take(500))
                .ToList();

and then get posts in each widget :

            var postsInGalery = postInWidgets
                .Where(wid => wid.WidgetID == 1).Take(6)
                .ToList();

            var postsInSpecialNews=postInWidgets
                .Where(wid => wid.WidgetID == 2).Take(5)
                .ToList();

            var postsInRecentNews=postInWidgets
                .Where(wid => wid.WidgetID == 5).Take(10)
                .ToList();

and in each Widget Partial View :

    foreach(var p in Model.PostsInRecentNews)
    {
        <li>@Html.ActionLink(p.Post.Title,"Index","Home")</li>
    }

My Question : How to Set the int value of Take(count) Dynamically for each widget instead of Take(6) , Take(5) , Take(10) ...

I think I need to use TakeWhile() instead the Take()

Thanks for any assistance...

Hamed
  • 61
  • 7

1 Answers1

1

It sounds like you just need to fetch the counts first (you may want to cache them):

var counts = db.Counts.ToDictionary<string, int>(c => c.Name, c => c.Count);

Then:

var postsInGallery = postInWidgets
    .Where(wid => wid.WidgetID == 1)
    .Take(counts["NewsGallery"])
    .ToList();

var postsInSpecialNews = postInWidgets
    .Where(wid => wid.WidgetID == 2)
    .Take(counts["SpecialNews"])
    .ToList();

var postsInRecentNews = postInWidgets
    .Where(wid => wid.WidgetID == 5)
    .Take(counts["RecentNews"])
    .ToList();

You could potentially use an enum instead of a string, to avoid the use of easily-typoed string constants. If the enum had a value of the related widget ID, you could wrap that up in a single method:

List<Widget> GetWidgets(WidgetType widgetType)
{
    return postInWidgets.Where(wid => wid.WidgetID == (int) widgetType)
                        .Take(counts[widgetType])
                        .ToList();
}

Then call it as:

var postsInGallery = GetWidgets(WidgetType.NewsGallery);
var postsInSpecialNews = GetWidgets(WidgetType.SpecialNews);
var postInRecentNews = GetWidgets(WidgetType.RecentNews);

(This assumes counts is a field somewhere, of course - adjust as per your requirements.)

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Thanks @Jon Skeet, I will use the second method, but is there a way to get Top(Count) of Posts that each widget needs to show in main query of postInWidgets? then take all in postsInRecentNews, Etc... – Hamed Aug 03 '15 at 09:30
  • @Hamed: I'm not sure I understand what you mean - are you asking whether you can perform a single query that retrieves the right number of each widget type? I suspect not. – Jon Skeet Aug 03 '15 at 09:31
  • Your answer is the same answer I was looking for, But exatly I prefer to have a single query that retrieves the right number of each posts that each widget needs. sorry for my english... – Hamed Aug 03 '15 at 09:46