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.
Automapper is considerably faster when mapping a List<T> of objects on . NET Core (It's still slower on full . NET Framework).
Defines a class used to provide values and methods to the component's view.
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.
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.
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.
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:-)
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