1

I was told to use automapper in the code below. I cannot get clarification for reasons that are too lengthy to go into. What object am I supposed to be mapping to what object? I don't see a "source" object, since the source is the database...

Would really appreciate any help on how to do this with automapper. Note, the actual fields are irrelevant, I need help with the general concept. I do understand how mapping works when mapping from one object to another.

public IQueryable<Object> ReturnDetailedSummaries(long orgId)
        {
            var summaries = from s in db.ReportSummaries
                where s.OrganizationId == orgId
                select new SummaryViewModel
                {
                    Id = s.Id,
                    Name = s.Name,
                    AuditLocationId = s.AuditLocationId,
                    AuditLocationName = s.Location.Name,
                    CreatedOn = s.CreatedOn,
                    CreatedById = s.CreatedById,
                    CreatedByName = s.User.Name,
                    OfficeId = s.OfficeId,
                    OfficeName = s.Office.Name,
                    OrganizationId = s.OrganizationId,
                    OrganizationName = s.Organization.Name,
                    IsCompleted = s.IsCompleted,
                    isHidden = s.isHidden,
                    numberOfItemsInAuditLocations = s.numberOfItemsInAuditLocations,
                    numberOfLocationsScanned = s.numberOfLocationsScanned,
                    numberOfItemsScanned = s.numberOfItemsScanned,
                    numberofDiscrepanciesFound = s.numberofDiscrepanciesFound
                };
            return summaries; 
        }
VSO
  • 11,546
  • 25
  • 99
  • 187

3 Answers3

3

It is a handy and a timesaver, especially if you use a one to one naming between translations layers. Here is how I use it.

For single item

public Domain.Data.User GetUserByUserName(string userName)
{
    Mapper.CreateMap<User, Domain.Data.User>();
    return (
        from s in _dataContext.Users
        where s.UserName==userName
        select Mapper.Map<User, Domain.Data.User>(s)
    ).SingleOrDefault();  
}

Multiple Items

public List<Domain.Data.User> GetUsersByProvider(int providerID)
{
    Mapper.CreateMap<User, Domain.Data.User>();
    return (
        from s in _dataContext.Users
        where s.ProviderID== providerID
        select Mapper.Map<User, Domain.Data.User>(s)
    ).ToList();  
}
Ross Bush
  • 14,648
  • 2
  • 32
  • 55
  • Thanks, I will try it and come back to accept the answer. – VSO Jul 12 '15 at 05:16
  • 2
    Do not use `Mapper.Map` with EF, it is going to query more data than is nessesary, It basically does a `Select * from ...` on your EF table. Use the `Project.To(` function instead in the [`AutoMapper.QueryableExtensions`](https://github.com/AutoMapper/AutoMapper/wiki/Queryable-Extensions) namespace. It is designed to work with `IQueryable` objects and will only query the columns that are actually used in the mapping. – Scott Chamberlain Jul 12 '15 at 05:34
  • The OP did not state that he was using EF. The example above uses the LinqToSql. – Ross Bush Jul 12 '15 at 05:42
  • @Scott Chamberlain: Is this the same as the explanation here: http://www.devtrends.co.uk/blog/stop-using-automapper-in-your-data-access-code I am trying it now. – VSO Jul 12 '15 at 05:44
  • 1
    @Scoot Chamberlain: That did it. Created a map like this: Mapper.CreateMap(); Then used the following: var summaries = db.DiscrepancyReportSummaries.Project().To(); Amazing how clever that is - no need to create some useless view just to map from. – VSO Jul 12 '15 at 05:52
  • @Irb: Looks like you knew the answer as well and didn't give it because of my poor phrasing. For sake of posterity, if you want to add this, I will accept your answer. Or if Scott wants to add one. I got a lot of help and I feel bad not accepting something. Thank you again guys. – VSO Jul 12 '15 at 05:53
  • 1
    I am glad to see that automapper is keeping up with times. I am still stuck on an oldish framework and was barely keeping up with what was being said, if anyone needs the kudos, its Scott, not me :) – Ross Bush Jul 12 '15 at 05:57
  • @VSO Yes it is the same explination, in fact that post is the birth of the Queryable Extensions. It got pulled in and added to the project after that article was written. – Scott Chamberlain Jul 12 '15 at 14:53
  • Thanks again Scott, you saved me a lot of time. – VSO Jul 12 '15 at 18:08
2

It looks like you already have a model? SummaryViewModel?

If this isn't the DTO, then presumably you want to do:

Mapper.CreateMap<SummaryViewModel, SummaryViewModelDto>();

SummaryViewModelDto summaryViewModelDto = 
    Mapper.Map<SummaryViewModel, SummaryViewModelDto>(summaryViewModel);

AutoMapper will copy fields from one object to another, to save you having to do it all manually.

See https://github.com/AutoMapper/AutoMapper/wiki/Getting-started

Nitesh Patel
  • 631
  • 3
  • 10
  • The "viewModel" is DTO, it is NOT a view model for the table in question as a whole. Trying Irb's solution atm, looks pretty clean. I do appreciate the reply. – VSO Jul 12 '15 at 05:25
1

The source is your entity class ReportSummary, the target is SummaryViewModel:

Mapper.CreateMap<ReportSummary, SummaryViewModel>();

The best way to use AutoMapper in combination with an IQueryable data source is through the Project.To API:

var summaries = db.ReportSummaries.Where(s => s.OrganizationId == orgId)
                  .Project().To<SummaryViewModel>();

Project.To translates the properties in the target model straight to the selected columns in the generated SQL.

Mapper.Map, on the other hand, only works on in-memory collections, so you can only use it when you first fetch complete ReportSummary objects from the database. (In this case there may not be much of a difference, but in other cases it can be substantial).

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