I have an EF model as follows:
On this model, I can obviously use Categories.Products
to receive a list of products.
I have a query as follows to return a list of Categories, with Products as a List to be used in an ASP.NET MVC 3 view:
var categories = (from a in context.Categories.Include("Products")
orderby a.SortOrder ascending
select a).ToList();
return View(categories);
In order to show the Products in order of their SortOrder I currently have to do:
<ul>
@foreach (var category in Model)
{
<li>@category.Title
<ul>
@foreach (var product in category.Products.OrderBy(a => a.SortOrder))
{
<li>@product.Description</li>
}
</ul>
</li>
}
</ul>
The offending line is: @foreach (var product in category.Products.OrderBy(a => a.SortOrder))
as this is handling a bit of my model in the view.
Is there a way to sort this in the query?
Is there a way to sort this in the query?
View models of course:
public class CategoryViewModel
{
public string Title { get; set; }
public IEnumerable<ProductViewModel> Products { get; set; }
}
public class ProductViewModel
{
public string Description { get; set; }
}
and in your controller action do the necessary to fill this view model:
public ActionResult Index()
{
var categories =
(from category in context.Categories
orderby category.SortOrder ascending
select new CategoryViewModel
{
Title = category.Title,
Products = category
.Products
.OrderBy(p => p.SortOrder)
.Select(p => new ProductViewModel
{
Description = p.Description
})
}).ToList();
).ToList();
return View(categories);
}
and in the Index.cshtml
view you can get rid of ugly loops and use display templates:
@model IEnumerable<CategoryViewModel>
<ul>
@Html.DisplayForModel()
</ul>
and inside the display template for a category (~/Views/Shared/CategoryViewModel.cshtml
)
@model CategoryViewModel
<li>
@Html.DisplayFor(x => x.Title)
<ul>
@Html.DisplayFor(x => x.Products)
</ul>
</li>
and inside the display template for a product (~/Views/Shared/ProductViewModel.cshtml
)
@model ProductViewModel
<li>
@Html.DisplayFor(x => x.Description)
</li>
As a further improvement to the controller action you could use AutoMapper to map between your domain models (EF objects) and your view models which should be passed to a view.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With