Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I manually populate ViewModel (Not using AutoMapper!)

Tags:

asp.net-mvc

I know there are a lot of posts on the subject but I cannot find one that helps me do what I want. I know that I will eventually be using Automapper but before I start playing with it, I want to learn how to do things manually. I want to create a ViewModel, populate it with values from my entities by way of a repository and send it to my View. As simple as this sounds, I am stuggling to get it done. I'm using MVC 3, EF 4.3, Database First. I have auto-generated my classes. I'm posting the relevant entities (abbreviated/renamed for this post) and classes, here is what I have so far:

Aggregate Entity: Shipping Header

using System;
using System.Collections.Generic;

namespace My.Models
{
public partial class ShippingHdr
{
    public ShippingHdr()
    {
        this.ShippingLI = new HashSet<ShippingLI>();
    }

    public int ID { get; set; }
    public int ShipToSiteID { get; set; }
    public Nullable<System.DateTime> DateShipped { get; set; }
    public Nullable<System.DateTime> EstDeliveryDate { get; set; }
    public string FromSitePOC { get; set; }
    public Nullable<int> ShipperID { get; set; }
    public string TrackingNo { get; set; }
    public string Comments { get; set;}
    public virtual Shippers Shippers { get; set; }
    public virtual ICollection<ShippingLI> ShippingLI { get; set; }
}

}

Here is my ViewModel

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace My.Models.ViewModels
{

public class ShippingHeaderSummaryVM
{
    public int ID { get; set; }
    public string Site { get; set; }
    public Nullable<System.DateTime> DateShipped { get; set; }
    public Nullable<System.DateTime> EstDeliveryDate { get; set; }
    public string TrackingNo { get; set; }
    public string HeaderComments { get; set; }
    public string Shipper { get; set; }
    public int NumOrders { get; set; }
    public string Site { get; set; }


}

}

Here is a query I got to return the items I want to use to populate my Viewmodel with. I believe the best place for this is in a Repository. I verified it returns the data I want using LinqPad (hence the missing reference to my dbContxt). I just don't know how to get the values from the query to the ViewModel:

var shipments = from h in c.ShippingHdrs
                        where (h.ShippingLI.Count > 1)
                        join
                        e in c.vHr_Employees on h.CreatedBy equals e.ID
                        join
                        s in c.Shippers on h.ShipperID equals s.ShipperID
                        join
                        r in vAaiomsSites on h.ShipToSiteID equals r.SiteID

                        select new
                        {
                            h.ID,
                            r.Site,
                            h.EstDeliveryDate,
                            h.DateShipped,
                            h.TrackingNumber,
                            h.HeaderComments,
                            e.LastName,
                            h.ShippingLI.Count,
                            s.Shipper
                                                        };

So what I want to do, again without using Automapper, is to populate the ViewModel with all of the rows from the ShippingHdr entity and pass it to my view.

Here are the filelds that need to be mapped:

ShippingHeaderSummaryVM mapped from shipments

ID = h.ID
Site = r.Site
DateShipped = h.DateShipped
EstDeliveryDate = h.EstDeliveryDate
TrackingNo = h.TrackingNumber
FromSitePOC = e.LastName
NumOrders = h.ShippingLI.Count
Shipper = s.Shipper
HeaderComments = h.HeaderComments

I am stuck here. How do I populate the ViewModel from the query? How then do I then call that action from my controller?

I hope I have given enough information, any help would be appreciated.

like image 378
Alan Fisher Avatar asked Jun 05 '12 23:06

Alan Fisher


People also ask

Is AutoMapper faster than manual mapping?

Automapper is considerably faster when mapping a List<T> of objects on . NET Core (It's still slower on full . NET Framework).

Can Viewmodel have methods?

Defines a class used to provide values and methods to the component's view.

Why use AutoMapper?

Use AutoMapper to eliminate the need to write tedious boilerplate code when mapping objects in your application. AutoMapper is a popular object-to-object mapping library that can be used to map objects belonging to dissimilar types.

Why use AutoMapper in ASP net Core?

AutoMapper is a simple library that helps us to transform one object type into another. It is a convention-based object-to-object mapper that requires very little configuration. The object-to-object mapping works by transforming an input object of one type into an output object of a different type.


2 Answers

In order to populate a list of shipments based on your view model object you would need to create a mapping method to map from your collection of shipments from your database to a collection of shipments based on your view model:

var model = new List<ShippingHeaderSummaryVM>();

foreach(var h in shipments)
{

    var viewModel = new ShippingHeaderSummaryVM
    {
    ID = h.ID
    Site = r.Site
    DateShipped = h.DateShipped
    EstDeliveryDate = h.EstDeliveryDate
    TrackingNo = h.TrackingNumber
    FromSitePOC = e.LastName
    NumOrders = h.ShippingLI.Count
    Shipper = s.Shipper
    HeaderComments = h.HeaderComments
    }

    model.Add(viewModel);
}

return model;

As a side note, this becomes a one liner after you have AutoMapper up and running:

var model = Mapper.Map<IEnumerable<ShippingHdr>, IEnumerable<ShippingHeaderSummaryVM>>(shipments);

While, learning how to do things manually is great. Manually mapping models doesn't really benefit you in any way or form. Go with AutoMapper.

like image 54
Jesse Avatar answered Sep 19 '22 12:09

Jesse


You can also use Linq to do something like this...

shipments.Select(h => new ShippingHeaderSummaryVM(){
    ID = h.ID,
    Site = r.Site,
    DateShipped = h.DateShipped,
    EstDeliveryDate = h.EstDeliveryDate,
    TrackingNo = h.TrackingNumber,
    FromSitePOC = e.LastName,
    NumOrders = h.ShippingLI.Count,
    Shipper = s.Shipper,
    HeaderComments = h.HeaderComments
});

Note that while mapping view models is great for passing to a view, always do it manually when reading from a view model to update your database.

Edit: Thanks for the typo correction:-)

like image 42
Nick Albrecht Avatar answered Sep 21 '22 12:09

Nick Albrecht