简体   繁体   中英

GroupBy with MVC Scaffolding

Background

I am currently working on an MVC project, in which I am looking to display a list of films and times in which they will be programmed to play. In order to achieve this, I have a basic table for this (summarised):

+-------------+----------------+
| FilmID (int)| Time (datetime)|
+-------------+----------------+
|  1          | 01:00          |
|  1          | 03:00          |
|  2          | 02:30          | 
+-------------+----------------+

This is linked to a 'FilmStore' in which basically gives information relating to synopsis/genre/etc.

Controller

I have set up a controller with the automatically-generated code:

public ActionResult Index()
{
    var filmShowings = db.FilmShowings.Include(f => f.FilmStore);

    return View(filmShowings.ToList());
}              

View

I have altered the preset view to

@foreach (var item in Model)
{
    <span>@Html.DisplayFor(modelItem => item.FilmID)</span>

    <div class="time slot">
       @Html.DisplayFor(modelitem => item.Time).ToString().Substring(0, 5)
    </div>
}

What I want

I am looking to groupBy the filmID within the view. So The filmID will display in a span, and for every record with that filmID will be displayed within a div. Something like:

1
   01:00
   03:00
2 
   02:30

What I've Tried

I have tried to add a groupby clause into the controller:

.GroupBy(f => f.FilmID);

and altered my view to:

  @foreach (var item in Model)
    {
            <span>@Html.DisplayFor(modelItem => item.FilmID)</span>
            @foreach(var group in groupItem.FilmID){
                <div class="time slot">
                   @Html.DisplayFor(myitem => group.Time).ToString().Substring(0, 5)
                </div>
            }
    }

I presumed a nested for loop would have allowed me to add this grouping. However, this inevitably failed. Would anyone be able to even point me in the right direction?

You can do this in 2 ways:

  1. Have your strongly typed model grouped by Film ID, ex: you will have a class that has 2 properties, FilmID and List, in your controller, you will retrieve the data and group it by FilmID and fill your model then pass it to the view and draw it the same way you did but instead of groupBy, You will simply iterate over the model using foreach and inside the foreach you will iterate over the list of times.
  2. Keep it as is without group by, and add a collapse/expand icon and on clicking the icon, fire an Ajax request passing the film ID and retrive the content as Partial view and draw this content in a span below the film ID, this option is better from performance perspective

The return of GroupBy is IEnumerable<IGrouping<TKey, TSource>> . Which means you end up essentially with a list of lists. The implementation of IGrouping will itself be an IEnumerable with the addition of a Key property, which will hold the value of the property you grouped by.

So, for your example, you would need to iterate over all the groups, and then for each group, iterate over the items in that group.

@foreach (var group in Model)
{
    <span>@Html.DisplayFor(modelItem => group.Key)</span>
    @foreach(var item in group){
        <div class="time slot">
           @Html.DisplayFor(myitem => item.Time).ToString().Substring(0, 5)
        </div>
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM