Tuesday, October 15, 2013

How to render grouped entities using strongly typed View in Asp.NET MVC?

In this post, we are going to learn how to show grouped entities using strongly typed Asp.net MVC View, for example, show all the products by subcategories as shown in the figure below. The first column shows the SubCategories and other columns show products. Another thing to notice is SubCategory’s Name property isn't populated more than once.  The style for just that row is colored and all other rows have background color as white.
image
I am using AdventureWorks2012 sample database for this example. I assume you know certain basics of Asp.Net MVC applications, little bit of LINQ and EntityFramework.  I am using database first approach with EntityFramework. 
  1. Create a basic Asp.net MVC4 Application. I am naming it as AspNetAjaxSamples101.  
  2. Add new empty Controller named HomeController
  3. Add a new ADO.NET Entity Data Model to your application.
  4. Open your HomeController and add following lines to your Index method.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using AspNetAjaxSamples101.Models;
namespace AspNetAjaxSamples101.Controllers
{
    public class HomeController : Controller
    {
        //
        // GET: /Home/
        private ADWorks2012Context db = new ADWorks2012Context();
        public ActionResult Index()
        {
            var ProductsBySubCategories = from y in db.ProductSubcategories
                                       from z in y.Products
                                       group z by y.Name into grp
                                       select grp;
 
            return View(ProductsBySubCategories.ToList());
        }
 
    }
}
We are passing the View an Object of type IEnumerable<IGrouping<string,AspNetAjaxSamples101.Models.Product>>. Add a new empty view to by right clicking on the View(ProductsBySubCategories.ToList()).
Copy the following code into your Index.cshtml page.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
@model IEnumerable<IGrouping<string,AspNetAjaxSamples101.Models.Product>>
 
@{
    ViewBag.Title = "Index";
}
 
<h3>
ProductsBySubcategories</h3>
<table>
    <thead>
<tr>
            <th>SubCategory</th>
            <th>Product</th>
            <th>ListPrice</th>
            <th>Color</th>
        </tr>
</thead>
    <tbody>
        @foreach (var item in Model)
        {
            var products = item.ToList();
                for(int i = 0; i <= products.Count() -1; i++)
                {
                    if (i == 0)
                    {
<tr class="trsubheader">
                        <td>
                            @item.Key.ToString()
                         </td>
                         <td>@products[i].Name</td>
                         <td>@products[i].ListPrice</td>
                         <td>@products[i].Color</td>
                     </tr>
}
                    else
                    {
<tr>
                         <td></td>
                         <td>@products[i].Name</td>
                         <td>@products[i].ListPrice</td>
                         <td>@products[i].Color</td>
                     </tr>
}
                }
        }
    </tbody>
</table>
Something about the code. Our view is a strongly typed view of type IEnumerable<IGrouping<string,AspNetAjaxSamples101.Models.Product>> that you can see on the top. Next piece of the puzzle is inside the tbody tag of table. First we do a foreach loop and get the group item then we iterate through each group item i.e. Product and show product details using for loop not foreach. The reason we use for loop is we want to know which row we are rendering. If it is the first row which we determine using the if statement then render SubCategory name using item.Key.ToString(). And if it is not the first row then skip the first td cell of the row and don’t show anything. Final piece in this project is styling. In the Site.css file add following style.
1
2
3
4
5
6
7
thead{
    background-color:#b75514;
    color:white;
}
.trsubheader{
    background-color:#eedacc;
}
In Index.cshtml page, inside second for loop if the i==0 then we assign class trsubheader to the row element of the table. So there you have it.