2

Having just figured out how to populate my ViewModel from a model using Automapper, I am now onto the next challenge – populating the ViewModel properties from a joined table.

The image below depicts my simple database.

enter image description here

My ViewModel class is defined as:

public class PersonViewModel
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public Nullable<int> Age { get; set; }
    public Nullable<int> SuffixId { get; set; }
    public string PersonStatus { get; set; }
    public string PersonPreference { get; set; }

    public virtual Suffix Suffix { get; set; }
}    enter code here

Note the additional fields of PersonStatus and PersonPreference that will come from joining PersonInfo to Person. Here is the code I use to instantiate my mapping configuration:

        Mapper.CreateMap<PersonViewModel, Person>();
        Mapper.CreateMap<Person, PersonViewModel>();

And now the code to populate the ViewModel

        List<PersonViewModel> persons = null;
        using (var context = new DemoEntities())
        {
            persons = (from p in context.People.AsEnumerable()
                       join i in context.PersonInfoes on p.Id equals i.PersonId
                    select Mapper.Map<PersonViewModel>(p)).ToList();
            return persons;
        }

How would I populate the two joined properties (PersonStatus and PersonPreference) from this setup?

Thanks in advance!

gilpach
  • 1,367
  • 3
  • 16
  • 34
  • Why are you joining PersonInfoes at all? EF will handle this for you automatically and automapper will map it. – Scottie Nov 27 '13 at 22:44
  • 1
    First a few questions: why the `AsEnumerable()` and how do you get one (of many) `PersonInfo`s? – Gert Arnold Nov 27 '13 at 22:45
  • Well, first, it's just a simple example I threw together so that I could pose the question. But Scottie, you say that AM will do it automatically. Can you elaborate? btw, person to personinfo is actually 1 to 1, not 1 to many. I'm trying to simulate a business rule we have on another system with this example. Gert, I was running into an error without the AsEnumerable(), I found this link which helped me resolve it: http://stackoverflow.com/questions/14770941/linq-and-automapper – gilpach Nov 27 '13 at 22:55

1 Answers1

4

AutoMapper can automatically flatten an object structure if the source and target classes meet some requirements.

  • The source class, the class that the mapping starts from, should have reference property to the related class. In you case: Person.PersonInfo (1:1, but n:1 will also work).1
  • The target class should contain property names that allow AutoMapper to resolve the property path to the referenced object. in your case: PersonViewModel.PersonInfoStatus, so AutoMapper will see that there's a property PersonInfo in the source object and a property Status in the referenced object.

If you've got these things in place, you can do

persons = context.People.Project().To<PersonViewModel>().ToList();

The Project().To syntax is a relatively new API that allows working on IQueryables. For more details see Does AutoMapper support Linq?.

You will see that this sends a JOIN query to the database.


1AutoMapper can also aggregate/flatten associated collections, but that's a different chapter.

Community
  • 1
  • 1
Gert Arnold
  • 105,341
  • 31
  • 202
  • 291