ASP.NET MVC : passing to view nested objects - asp.net-mvc

I have the following model :
public class Business
{
[Key]
public int BusinessId { get; set; }
public string Name {get;set;}
....
.....
....
[Display(Name = "Owner")]
public int OwnerId { get; set; }
[ForeignKey("OwnerId")]
public ApplicationUser Owner { get; set; }
}
In my controller I have the following function :
public async Task<IActionResult> Index()
{
return View(await _context.Business.ToListAsync());
}
and my view :
#model IEnumerable<ServiceProviderApp.Models.Business>
#{
ViewData["Title"] = "Business Engine";
}
.....
......
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
......
<td>
#Html.DisplayFor(modelItem => item.Owner.Name)
</td>
<td>
As you can understand, the Owner inside the Business is an Object. Therefore, when I try to access it in the view (item.Owner.Name) I don't get anything (null). I can change the query on the controller to return a record that is joined but then the model on the view won't be business any more.
I searched online but didn't find a good and clear explanation. Not sure why the EF doesn't bind the nested objects automatically.
One option that I saw on YouTube but I think that it sucks to do:
Create a new model with all the columns after the join
In my controller, run the join and pass it to the view
In the view accept the new model as parameter
Link - https://www.youtube.com/watch?v=v1B3R-kb9CU

Solution : You need to use the include func in the controller :
public async Task<IActionResult> Index()
{
var business = _context.Business.Include("Owner");
return View(await business.ToListAsync());
}
Thanks to DanielShabi for the help.

Related

Eager Loading - MVC

I have 2 models: (1) FamiliaMáquina (PK: FamiliaId) and (2) TipoMáquina (PK: TipoMáquinaId).
The relation between these is: TipoMáquina can have only 1 FamiliaId associated, while FamiliaMáquina can have many TipoMáquinaId associated (one to many relationship).
FamiliaMáquina definition:
public class FamiliaMáquina
{
[Key, Required]
public int FamiliaId { get; set; }
public string DescripciónFamilia { get; set; }
public virtual ICollection<TipoMáquina> TipoMáquina { get; set; }
}
TipoMáquina definition:
public class TipoMáquina
{
[Key, Required]
public int TipoMáquinaId { get; set; }
public string DescripciónTipoMáq { get; set; }
public int FamiliaId { get; set; }
public virtual FamiliaMáquina FamiliaMáquina { get; set; }
}
The objetive: Show, programing the FamiliaMáquina controller, a list of FamiliaId (from model 1) and DescripciónTipoMáq (from model 2) associated. For this, the tables have been populated with sample data.
On the FamiliaMaqController (where the association takes places - eager loading):
public class FamiliaMaqController : Controller
{
private ApplicationDbContext _context;
public FamiliaMaqController()
{
_context = new ApplicationDbContext();
}
protected override void Dispose(bool disposing)
{_context.Dispose();}
public async Task<ActionResult> NuevaMQ()
{
var fammáquinas = _context.FamiliaMáquinas.Include(c => c.TipoMáquina).AsNoTracking();
return View(await fammáquinas.ToListAsync());
}
}
This is supossed to show on NuevaMQ.cshtml. NuevaMQ code is:
#model IEnumerable<Plataforma.Models.FamiliaMáquina>
#{
ViewBag.Title = "NuevaMQ";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>NuevaMQ</h2>
<table class="table table-bordered table-hover">
<thead>
<tr>
<th>Familia de Máquina</th>
<th>Tipo de Máquina</th>
</tr>
</thead>
<tbody>
#foreach (var fammáquinas in Model)
{
<tr>
<td>#Html.DisplayFor(modelItem => fammáquinas.FamiliaId)</td>
<td>#Html.DisplayFor(modelItem => fammáquinas.TipoMáquina.DescripciónTipoMáq)</td>
</tr>
}
</tbody>
</table>
I'm getting an error on this line:
#Html.DisplayFor(modelItem => fammáquinas.TipoMáquina.DescripciónTipoMáq
Supposedly, FamiliaID and DescripciónTipoMáq should be listed, however, I get the following warning:
"ICollection doesn't have a definition for 'DescripciónTipoMáq'."
¿Why isn't eager loading working? I've been struggling with this for a while now. It's like this line of code:
var fammáquinas = _context.FamiliaMáquinas.Include(c => c.TipoMáquina).AsNoTracking();
Is not associating the tables but I'm not getting an error there.
What I'm getting as a result in the website is:
FamiliaId: 1
DescripciónTipoMáq: System.Data.Entity.DynamicProxies.FamiliaMáquina_EB64915DB33A48C74F57D392EFE55D5AEDC5BF74BE67B819F4737EEB09B6F436
This repeats as many times as items related per FamiliaId. It's like the program is iterating as it should but getting that reference everytime instead of the field value.
You've the error in that line
#Html.DisplayFor(modelItem => fammáquinas.TipoMáquina.DescripciónTipoMáq)
Because based on the code of FamiliaMáquina class you're using TipoMáquina which is a collection ICollection<TipoMáquina>. And ICollection<TipoMáquina> likee all ICollection<T> doesn't define DescripciónTipoMáq property that is what the error said:
ICollection doesn't have a definition for 'DescripciónTipoMáq'.
So if you wan't to get the description you need to iterate through each TipoMáquina item and display DescripciónTipoMáq property
Side Note: Avoid using that kind of naming things with accent because you or another developper can lost a lot of time to know why the code doesn't compile and will find that after several minutes that he or she mispelled the name of the varaible.
It worked!
I've changed the controller in this way:
public async Task<ActionResult> NuevaMQ()
{
var fammáquinas = _context.TipoMáquinas.Include(c => c.FamiliaMáquina).AsNoTracking();
return View(await fammáquinas.ToListAsync());
}
Then, I went to the view to change it accordingly so I could invok the data from FamiliaMáquina and brind the FamiliaId:
<tbody>
#foreach (var fammáquinas in Model)
{
<tr>
<td>#Html.DisplayFor(modelItem => fammáquinas.FamiliaId)</td>
<td>##Html.DisplayFor(modelItem => fammáquinas.DescripciónTipoMáq)</td>
</tr>
}
</tbody>
also, changed the model of reference at top of the cshtml file:
#model IEnumerable<Plataforma.Models.TipoMáquina>
And as result, the table showed both atributes invoked from diferent tables :) Thanks for the help!

ASP MVC Nested Models

I need a view that displays rows of header-detail info. For a trivial case I set up a Course-Student tiny database with 4 simple tables. The Courses and Students tables are linked with a Section table which also has a student grade in it. Also, the Student table is owned by a Student Type Table. There are helper classes to hold the list of "header" data for the course and a "detail" list for each student who takes that class.
namespace SchoolA.Models
{
public class CourseInfo2
{
public int CourseID { get; set; }
public int CourseNumber { get; set; }
public string CourseName { get; set; }
public IEnumerable<CourseSectionList> CourseStudentList { get; set; }
}
}
namespace SchoolA.Models
{
public class CourseSectionList
{
public string Student { get; set; }
public string Type { get; set; }
public string Grade { get; set; }
}
}
The controller is:
public ActionResult Courselisting()
{
List<CourseInfo2> courseInfo2 = new List<CourseInfo2>();
List<CourseSectionList> courseSectionList = new List<CourseSectionList>();
var Cquery = from c in db.Courses select c;
foreach (var item in Cquery)
{
Course course = db.Courses.Find(item.CourseID); // first find the selected course
// get the sections
foreach (var s in query) // go through each section
{
// get the section data
courseSectionList.Add(new CourseSectionList
{
Student = student.StudentName,
Type = studentType.StudentTypeName,
Grade = s.SectionStudentGrade
});
} // end of section loop
courseInfo2.Add(new CourseInfo2
{
CourseID = course.CourseID,
CourseNumber = course.CourseNumber,
CourseName = course.CourseName,
CourseStudentList = courseSectionList
});
} // end of Course loop
return View(courseInfo2); // Course List and Section list for each course
}
The View is:
#model SchoolA.Models.CourseInfo2
#* doesn't work either: model List<SchoolA.Models.CourseInfo2>*#
<div>
<table>
<tr><th>ID</th> <th>Number</th> <th>Course</th></tr>
#foreach (var CourseInfo2 in Model)
{
<tr>
<td>
#CourseInfo2.CourseID
</td>
<td>
#CourseInfo2.CourseNumber
</td>
<td>
#CourseInfo2.CourseName
</td>
<td>
<table class="table">
<tr><th>Student</th> <th>Type</th><th>Grade</th></tr>
#foreach (var s in Model.CourseStudentList)
{
<tr>
<td>
#s.Student
</td>
<td>
#s.Type
</td>
<td>
#s.Grade
</td>
</tr>
}
</table>
</td>
</tr>
}
</table>
</div>
The problem is that I get a variety of errors as I try to pass these two models to the view. In the code as shown above I get this error:
CS1579: foreach statement cannot operate on variables of type 'SchoolA.Models.CourseInfo2' because 'SchoolA.Models.CourseInfo2' does not contain a public definition for 'GetEnumerator'
I've tried a number of variations for passing the models but always run into one error other the other that prevents both models from working in the view. I should note that I tested each part of the view independently and the controller code works fine to deliver the correct data to the view. However, I can't combine the two.
The problem seems to be the way I create instances of the models an how they are passed to the view. What am I doing wrong?
You're passing your view a List<SchoolA.Models.CourseInfo2>, but the view expects a single SchoolA.Models.CourseInfo2.
Change your #model declaration to IEnumerable<SchoolA.Models.CourseInfo2>.
Then change your foreach loops.
Change the first loop to foreach (var courseInfo in Model)
Change the inner loop to foreach (var s in courseInfo.CourseStudentList)
You are passing a model which is list of object, while in view you have single object.
Change your view model bind as below:
#model List<SchoolA.Models.CourseInfo2>
Problem: I have to edit Level2Name (by UI it's a textbox inside the child grid).
I'm able to edit Level1name (parent grid text field) and able to get value in my controller.
Question: How do I able to edit the nested textbox.
What I've tried.
Code:
Model
public class Level0
{
public Level0()
{
Level1= new List<Level1>();
}
public int? ID{ get; set; }
public int? NameText{ get; set; }
public List<Level1> lev1{ get; set; }
}
public class Level1
{
public Level1()
{
Level2= new List<Level2>();
}
public int Lev1ID {get;set;}
public string Level1name{ get; set; }
public List<Level2> level2{ get; set; }
}
public class Level2
{
public string Level2_ID { get; set; }
public string Level2Name{ get; set; }
}
UI Code
#for (int i = 0; i < Model.Level1.Count; i++)
{
#Html.HiddenFor(modelItem => Model.Floors[i].Lev1ID )
#for (int j = 0; j < Model.Level1[i].Level2.Count; j++)
{
#Html.HiddenFor(m => m.Level1[i].Level2[j].OP)
#Html.TextBoxFor(m => m.Level1[i].Level2[j].Level2Name, new { #class = "form-control" })
}
}

Using 2 models in one view in ASP.NET MVC 5

I am new to ASP.NET MVC and I am kindly asking you to help me with this problem:
I have 2 models - Delegation:
public int idDelegation { get; set; }
public string Delegation_Name { get; set; }
public string Employee_Name { get; set; }
and Project:
public int idProject { get; set; }
public string Project_System_Name { get; set; }
public string Project_System_ID { get; set; }
I want to display in a view a list of current delegations and projects, with the Edit/Details/Delete options for each one.
I created a ViewModel DelegationProject:
public class DelegationProject
{
public IEnumerable<Delegation> delegations { get; set; }
public IEnumerable<Project> projects { get; set; }
}
In my Index view I have:
#model IEnumerable<....ViewModel.DelegationProject>
<table class="table">
<tr>
<th>#Html.DisplayNameFor(model => model.delegations.Employee_Name</th>
<th>#Html.DisplayNameFor(model => model.delegations.Delegation_Name</th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>#Html.DisplayFor(itemModel => item.delegations.Employee_Name)</td>
<td>#Html.DisplayFor(itemModel => item.delegations.Delegation_Name</td>
<td>
#Html.ActionLink("Edit", "Edit", new { x => x.idDelegation }) |
#Html.ActionLink("Details", "Details", new { x => x.idDelegation }) |
#Html.ActionLink("Delete", "Delete", new { x => x.idDelegation })
</td>
</tr>
}
</table>
When I run the application, I get these error messages:
Description: An error occurred during the compilation of a resource required to service this request. Please review the following specific error details and modify your source code appropriately.
Compiler Error Message: CS1061: 'System.Collections.Generic.IEnumerable' does not contain a definition for 'Employee_Name' and no extension method 'Employee_Name' accepting a first argument of type 'System.Collections.Generic.IEnumerable' could be found (are you missing a using directive or an assembly reference?)
I tried different things (like List<> or Tuple) from stackoverflow topics and other sites posts, but I wasn't able to use to models in the same view and iterate through them.
I managed to find a solution for this problem.
The ViewModel DelegationProject remained the same, in my controller for Index action I have:
public ActionResult Index()
{
DelegationProject viewModel = new DelegationProject();
viewModel.delegations = GetDelegations();
viewModel.projects = GetProjects();
return View(viewModel);
}
And I created two methods in the respective controller - GetDelegations() and GetProjects():
public List<Delegation> GetDelegations()
{
var deleg = db.Delegation.Include(d => d.Project);
var list = new List<Delegation>(deleg).ToList();
return list;
}
public List<Project> GetProjects()
{
var projects = db.Project.Include(p => p.Country);
var list = new List<Project>(projects);
return list;
}
My View looks like this:
#model .......ViewModel.DelegationProject
#foreach (var item in Model.delegations)
{
<tr>
<td>
#Html.DisplayFor(itemModel => item.Employee_Name)
</td>
<td>
#Html.DisplayFor(itemModel => item.Delegation_Name)
</td>
</tr>
}
Hope this could be of any help to somebody.

How to use two IENumerable models in one view

I am trying to use two models in one view, but from what I understand my program just don't see any objects within models.
Here is my code.
Models:
public class Album
{
[Key]
public int ThreadId { get; set; }
public int GenreId { get; set; }
public string Title { get; set; }
public string ThreadByUser { get; set; }
public string ThreadCreationDate { get; set; }
public string ThreadContent { get; set; }
public Genre Genre { get; set; }
public List<Posts> Posty { get; set; }
}
public class Posts
{
[Key]
public int PostId { get; set; }
public int ThreadId { get; set; }
public string PostTitle { get; set; }
public string PostContent { get; set; }
public string PostDate { get; set; }
public string PosterName { get; set; }
public Album Album { get; set; }
}
public class ModelMix
{
public IEnumerable<Posts> PostsObject { get; set; }
public IEnumerable<Album> ThreadsObject { get; set; }
}
Index controller code:
public ActionResult Index(int id)
{
ViewBag.ThreadId = id;
var posts = db.Posts.Include(p => p.Album).ToList();
var albums = db.Albums.Include(a => a.Genre).ToList();
var mixmodel = new ModelMix
{
PostsObject = posts,
ThreadsObject = albums
};
return View(mixmodel);
}
View code:
#model MvcMusicStore.Models.ModelMix
<h2>Index</h2>
#Html.DisplayNameFor(model => model.PostsObject.PostContent)
And when I try to execute my program I am getting this error:
CS1061: The "
System.Collections.Generic.IEnumerable 'does not contain a definition
of" PostContent "not found method of expanding" PostContent ", which
takes a first argument of type' System.Collections.Generic.IEnumerable
"
How I can make it work as intended? There are a lot of questions like mine on the internet but I couldn't find any matching my case.
Looping over models can be a little confusing to begin with in MVC, only because the templated helpers (i.e. Html.DisplayFor and Html.EditorFor) can be provided templates which the helper will automatically invoke for every element in a collection. That means if you're new to MVC, and you don't realise a DisplayTemplate or an EditorTemplate has not been provided for the collection already, it looks as though a simple:
#Html.DisplayFor(m => m.SomePropertyThatHoldsACollection)
is all you need. So if you've seen something like that already, that might be why you made the assumption it would work. However, let's assume for a moment that a template has not been provided. You have two options.
Firstly, and most simply, would be to use foreach over the collection:
#foreach (var post in Model.PostsObject)
{
#Html.DisplayFor(m => post.PostTitle)
// display other properties
}
You could also use a for loop, but with IEnumerable<T>, there is no indexer, so this won't work:
#for (int i = 0; i < Model.PostsObject.Count(); i++)
{
// This generates a compile-time error because
// the index post[i] does not exist.
// This syntax would work for a List<T> though.
#Html.DisplayFor(m => post[i].PostTitle)
// display other properties
}
If you did want to use the for loop still, you can use it like so:
#for (int i = 0; i < Model.PostsObject.Count(); i++)
{
// This works correctly
#Html.DisplayFor(m => post.ElementAt(i).PostTitle)
// display other properties
}
So use whichever you prefer. However, at some point it would be a good idea to look into providing templates for your types. (Note: Although this article was written for MVC 2, the advice still applies.) They allow you to remove looping logic from your views, keeping them cleaner. When combined with Html.DisplayFor, or Html.EditorFor, they will also generate correct element naming for model binding (which is great). They also allow you to reuse presentation for a type.
One final comment I'd make is that the naming of your properties is a little verbose:
public class ModelMix
{
public IEnumerable<Posts> PostsObject { get; set; }
public IEnumerable<Album> ThreadsObject { get; set; }
}
We already know they're objects, so there's no need to add that on the end. This is more readable:
public class ModelMix
{
public IEnumerable<Posts> Posts { get; set; }
public IEnumerable<Album> Threads { get; set; }
}
You need to iterate them like this:
#model MvcMusicStore.Models.ModelMix
<h2>Index</h2>
#for(var i=0; i<model.PostsObject.Count(); i++)
{
#Html.DisplayNameFor(model => model.PostsObject[i].PostContent)
}
And also it's better to save IList instead of IEnumerable, as it will have Count property, instead of using Count() method
Typically you'll need to iterate through each item if you're passing in any type of IEnumerable<>. Since you built a semi-complex model, you'll want to display foreach item in each list. Here is an example based from the ASP.NET MVC tutorials that I think would help you a bit:
#model IEnumerable<ContosoUniversity.Models.Course>
#{
ViewBag.Title = "Courses";
}
<h2>Courses</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.CourseID)
</th>
<th>
#Html.DisplayNameFor(model => model.Title)
</th>
<th>
#Html.DisplayNameFor(model => model.Credits)
</th>
<th>
Department
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.CourseID)
</td>
<td>
#Html.DisplayFor(modelItem => item.Title)
</td>
<td>
#Html.DisplayFor(modelItem => item.Credits)
</td>
<td>
#Html.DisplayFor(modelItem => item.Department.Name)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.CourseID }) |
#Html.ActionLink("Details", "Details", new { id=item.CourseID }) |
#Html.ActionLink("Delete", "Delete", new { id=item.CourseID })
</td>
</tr>
}
</table>
Generally most people use an ICollection for their lists, where an example might be in an object:
public virtual ICollection<Post> Posts { get; set; }
Source:
http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/reading-related-data-with-the-entity-framework-in-an-asp-net-mvc-application
I would recommend starting at the beginning as it'll help you understand why you need to do this:
http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc

ViewModel Implementation in ASP.NET MVC - Is this code best practice?

I've just started to get into using ViewModels. Can you guys check out this code to see if I'm following best practice? Is there anything out of the ordinary? Would you do the validation differently?
Sorry if code is lengthy (there's so many parts to it). I've tried to make it as easy to understand as possible.
Thanks!
Model
public class CustomerModel
{
[Required(ErrorMessage="Primer nombre!")]
public string FirstName { get; set; }
[Required(ErrorMessage="Segundo nombre!")]
public string LastName { get; set; }
[Required(ErrorMessage="Edad")]
public int? Age { get; set; }
public string State { get; set; }
public string CountryID { get; set; }
[Required(ErrorMessage="Phone Number")]
public string PhoneNumber { get; set; }
}
ViewModel
public class CustomerViewModel
{
public CustomerModel Customer { get; set; }
public string Phone1a { get; set; }
public string Phone1b { get; set; }
public string Phone1c { get; set; }
}
Controller
public ActionResult Index()
{
CustomerViewModel Customer = new CustomerViewModel()
{
Customer = new CustomerModel(),
};
return View(Customer);
}
[HttpPost]
public ActionResult Index(CustomerViewModel c)
{
//ModelState.Add("Customer.PhoneNumber", ModelState["Phone1a"]);
// Let's manually bind the phone number fields to the PhoneNumber properties in
// Customer object.
c.Customer.PhoneNumber = c.Phone1a + c.Phone1b + c.Phone1c;
// Let's check that it's not empty and that it's a valid phone number (logic not listed here)
if (!String.IsNullOrEmpty(c.Customer.PhoneNumber))
{
// Let's remove the fact that there was an error!
ModelState["Customer.PhoneNumber"].Errors.Clear();
} // Else keep the error there.
if (ModelState.IsValid)
{
Response.Write("<H1 style'background-color:white;color:black'>VALIDATED</H1>");
}
return View("Index", c);
}
}
View
#model MVVM1.Models.CustomerViewModel
#using (Html.BeginForm("Index", "Detail"))
{
<table border="1" cellpadding="1" cellspacing="1">
<tr>
<td>#Html.LabelFor(m => m.Customer.FirstName)</td>
<td>
#Html.TextBoxFor(m => m.Customer.FirstName)
#Html.ValidationMessageFor(m => m.Customer.FirstName)
</td>
</tr>
<tr>
<td>#Html.LabelFor(m => m.Customer.LastName)</td>
<td>
#Html.TextBoxFor(m => m.Customer.LastName)
#Html.ValidationMessageFor(m => m.Customer.LastName)
</td>
</tr>
<tr>
<td>#Html.LabelFor(m => m.Customer.Age)</td>
<td>
#Html.TextBoxFor(m => m.Customer.Age)
#Html.ValidationMessageFor(m => m.Customer.Age)
</td>
</tr>
<tr>
<td>#Html.LabelFor(m => m.Customer.PhoneNumber)</td>
<td width="350">
#Html.TextBoxFor(m => m.Phone1a, new { size="4", maxlength="3" })
#Html.TextBoxFor(m => m.Phone1b)
#Html.TextBoxFor(m => m.Phone1c)
<div>
#Html.ValidationMessageFor(m => m.Customer.PhoneNumber)
</div>
</td>
</tr>
<tr>
<td></td>
<td>
<input type="submit" value="Submit" /></td>
</tr>
</table>
}
One thing that jumps out at me is this:
if (ModelState.IsValid)
{
Response.Write("<H1 style'background-color:white;color:black'>VALIDATED</H1>");
}
return View("Index", c);
Remember that view models are good for passing data to your controller AND back to your model. I recommend you add an IsValid property to your view model and then setting that to true instead of calling Response.Write. Then simply add this to the top of your partial view:
#if (Model.IsValid)
{
<H1 style'background-color:white;color:black'>VALIDATED</H1>
}
You can also get to ModelState in your view but some would argue that isn't a best practice. However, if you don't want to add a property to your model for something you can just see in your view you can just do this:
#if (ViewData.ModelState.IsValid)
Another nitpicky thing is that MVC validation attributes are typically used for validation on the UI. This validation can be reused in other areas but in some cases is sub-optimal. Also, you may not always be able to modify your domain models. Therefore, to keep all of my UI validation in one place I usually wrap my domain models in my view models so you get something like this:
public class CustomerViewModel
{
public CustomerModel Customer { get; set; }
[Required(ErrorMessage="Primer nombre!")]
public string FirstName
{
get { return Customer.FirstName; }
set { Customer.FirstName = value; }
}
...
This may seem redundant and isn't always worth the effort but it is a good practice to consider when using Entity Framework domain models or other classes which are difficult or impossible to modify.
I'm just getting the hang of MVC myself, but I researched this same topic yesterday and came to the conclusion that one should not directly include a model object in the ViewModel. So my understanding is that it would be a bad practice to include your CustomerModel directly in the CustomerViewModel.
Instead, you want to list out each of the properties from CustomerModel that you want to include in your ViewModel. Then you either want to manually map the data from CustomerModel to the CustomerViewModel or use a tool like AutoMapper which does it automatically with a line of code like this inside of your action method:
public ViewResult Example()
{
// Populate/retrieve yourCustomer here
Customer yourCustomer = new CustomerModel();
var model = Mapper.Map<CustomerModel, CustomerViewModel>(yourCustomer);
return View(model);
}
In this case, Mapper.Map will return a CustomerViewModel that you can pass to your View.
You will also need to include the following in your Application_Start method:
Mapper.CreateMap<CustomerModel, CustomerViewModel>();
In general I found AutoMapper pretty easy to get to work. It's automatic when the field names match, if they don't or you have a nested Object, you can specify those mappings in the CreateMap line. So if your CustomerModel uses an Address object instead of individual properties, you would do this:
Mapper.CreateMap<CustomerModel, CustomerViewModel>()
.ForMember(dest => dest.StreetAddress, opt => opt.MapFrom(src => src.Address.Street));
Please anyone correct me if I'm wrong as I'm just getting my head around MVC as well.
I would say your ViewModel implementation is pretty standard. You are using the ViewModel to act as the intermediate object between your View, and your Domain Model. Which is good practice.
The only thing I'd be weary about is how you handle Model errors, and also your ViewModel should have some attributes. For instance, you might want to use the RegularExpressionAttribute Class:
public class CustomerViewModel
{
public CustomerModel Customer { get; set; }
[RegularExpression(#"^\d{3}$")]
public string Phone1a { get; set; }
[RegularExpression(#"^\d{3}$")]
public string Phone1b { get; set; }
[RegularExpression(#"^\d{4}$")]
public string Phone1c { get; set; }
}

Resources