LINQ : How to set value of Take() from a field in current query

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...

Jon Skeet
people
quotationmark

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

people

See more on this question at Stackoverflow