Search code examples
asp.net-mvcasp.net-mvc-4viewmodelasp.net-mvc-viewmodel

asp mvc list product details in view using View Model


I am trying to list single product details in a view. The product specification changes dynamically because specifications are added row-wise in table, which means we can add huge number of specifications for each product (as done in ecommerce sites). Right now I am able to meet the requirement using ViewBag, but I am deciding to use ViewModel as a better practice.

Model class:

// Product:
public partial class ProductTable
{
    public ProductTable()
    {
        this.SpecificationsTable = new HashSet<SpecificationsTable>();
    }

    public int ProductID { get; set; }
    public string Title { get; set; }
    public string SmallDescription { get; set; }
    public string FullDescription { get; set; }

    public virtual ICollection<SpecificationsTable> SpecificationsTable { get; set; }
    }

//Specifications:
public partial class SpecificationsTable
{
    public int SpecificationsID { get; set; }
    public string SpecificationName { get; set; }
    public string SpecificationValue { get; set; }
    public Nullable<int> ProductID { get; set; }
    public virtual ProductTable ProductTable { get; set; }
}

ViewModel:

public class DetailsViewModel
{
    public int ProductID { get; set; }
    public string Title { get; set; }
    public string SmallDescription { get; set; }
    public string FullDescription { get; set; }
    public string SpecificationName { get; set; }
    public string SpecificationValue { get; set; }
}

ActionMethod

public ActionResult ProductDetails(int id)
{
    var details = (from c in dbo.ProductTable
                   join s in dbo.SpecificationsTable 
                   on c.ProductID equals s.ProductID
                   where c.ProductID == id
                   select new DetailViewModel
                   {
                       Title = c.Title,
                       SmallDescription = c.SmallDescription,
                       FullDescription = c.FullDescription
                   }).ToList();

     // To remove repeated product title , small and full description
     var distinctItems = details.GroupBy(x => x.ProductID).Select(y => y.First());

     // To show product title, small and full description for this product

     ViewBag.ProductDetails = distinctItems;

     var specifications = (from c in dbo.ProductTable
                             join s in dbo.SpecificationsTable 
                             on c.ProductID equals s.ProductID
                             where c.ProductID == id
                             select new DetailViewModel
                             {
                                 SpecificationName = s.SpecificationName,
                                 SpecificationValue = s.SpecificationValue
                             }).ToList();

    // To show list of specifications for this product
    ViewBag.Specifcations = specifications;
    return View();
}

expected output in view:

Details:

Title: New Samsung offer

SmallDescription : Something small 

FullDescription : Something full

Specifcations:

Mobile Name :Samsung

Model : 2015

Price : 70 $

Color:  White

I am using database first method and I am trying to learn how we can use view model here.


Solution

  • You current view model does not reflect what you want to display in the view, which is multiple specification for each product, so you need a collection property. Change your view models to

    public class SpecificationVM
    {
      public string Name { get; set; }
      public string Value { get; set; }
    }
    public class ProductVM
    {
      public string Title { get; set; }
      public string SmallDescription { get; set; }
      public string FullDescription { get; set; }
      IEnumerable<SpecificationVM> Specifications { get; set; }
    }
    

    Then in the controller, populate you view model using

    public ActionResult ProductDetails(int id)
    {
      var product = db.ProductTable.Where(p => p.ProductID == id).FirstOrDefault();
      // note you may need to add .Include("SpecificationsTable") in the above
      if (product == null)
      { 
        return new HttpNotFoundResult();
      }
      ProductVM model = new ProductVM()
      {
        Title = product.Title,
        SmallDescription = product.SmallDescription,
        FullDescription = product.FullDescription,
        Specifications = product.SpecificationsTable.Select(s => new SpecificationVM()
        {
          Name = s.SpecificationName,
          Value = s.SpecificationValue
        })
      };
      return View(model);
    }
    

    Then in the view

    @model yourAssembly.ProductVM
    <h2>Details</h2>
    @Html.DisplayNameFor(m => m.Title)
    @Html.DisplayFor(m => m.Title)
    .... // ditto for SmallDescription and FullDescription 
    <h2>Specifications</h2>
    @foreach(var item in Model.Specifications)
    {
      @Html.DisplayFor(m => item.Name)
      @Html.DisplayFor(m => item.Value)
    }