Data projection in Entity Framework and Automapper

I want to use AutoMapper to construct a ViewModel (flattening - data projection) for use in an ASP.net MVC app.

var tmp = from x in db.Mailings select Mapper.Map<Mailing, MailingViewModel>(x);
return View(tmp.ToList());

Of course, when I try the sample above, I get the EF error "LINQ to Entities does not recognize the method ... method, and this method cannot be translated into a store expression."

I know it's possible to move the .ToList() before the Automapper does its magic, but then I fetch all the fields from the Db (and I only need 3 of 20 fields)

Is it possible to use that in a clean way. Clean = Not all the fields are fetched from the DB, but only the fields necessary for the ViewModel. Is it possible in Automapper? Or perhaps an other library? (without doing it manually ;) )

Answers


Yes this is very possible. See here http://www.devtrends.co.uk/blog/stop-using-automapper-in-your-data-access-code

Edit: I've recently found that the basis to this already exists in AutoMapper. add a using statement for AutoMapper.QueryableExtensions and you are provided with an IQueryable extension called Project<>()


You can simply call:

var tmp = from x in db.Mailings 
          select new MailingViewModel
            {
               FirstName = x.FirstName,
               LastName = x.LastName,
               Address = x.Address
            };

You don't need AutoMapper for simple projection if you access EF directly in controller.

You can't involve AutoMapper in linq-to-entities query - no way. You must either return entity (or another projected object) and map it by AutoMapper or use plain projection without AutoMapper.


This is caused by the way linq interacts with IQueryableProviders ( I think this is the interface ).

So what is happening is that Linq is getting compiled to an expression tree which the underlying linq provider reads and tries to convert to sql. The linq provider has no idea how to translate Mapper.Map<> into SQL hence the error.

For a good video on how linq providers work check out: http://channel9.msdn.com/Shows/Going+Deep/Erik-Meijer-and-Bart-De-Smet-LINQ-to-Anything


You should be able to do this using AutoMapper's DynamicMap. I believe something like the following sill solve your issue if you really want to use AutoMapper, although in this particular case I agree with Ladislav Mrnka.

var tmp = from x in db.Mailings 
          select new
          {
              FirstName = x.FirstName,
              LastName = x.LastName,
              Address = x.Address
          };

return View(tmp.ToList().Select(item => Mapper.Map<MailingViewModel>(item)));

Unfortunately, if you want to limit the columns you're returning from the database you need to specify which ones you want, which does defeat the purpose of AutoMapper in this scenario. This would be a really neat AutoMapper extension though, to take the destination type and dynamically create a select expression based on the type's properties.


This can be done using LINQ Projector library. It is based on http://www.devtrends.co.uk/blog/stop-using-automapper-in-your-data-access-code and adds some mapping conventions.


since Automapper doesn't work directly to database (need to transform to in-memory object before addressing it), I've written own simple class to copy identical properties:

Initial code:

  model.Sales = _dbcontext.Sales.Where(o => o.PartnerId == PartnerId && (o.SaleDate > model.BeginDate || model.BeginDate == null) && (o.SaleDate <= model.EndDate || model.EndDate == null)).Select(o => new SaleViewModel
        {
            NumberIn1S = o.NumberIn1S,
            Total = o.Total,
            SaleDate = o.SaleDate,
            Comments = o.Comments,
            Driver = o.Driver,
            GuidIn1S = o.GuidIn1S
        }).OrderByDescending(o => o.SaleDate).ToList(); </p>

MyMapper:

model.Sales = _dbcontext.Sales.Where(o => o.PartnerId == PartnerId && (o.SaleDate > model.BeginDate || model.BeginDate == null) && (o.SaleDate <= model.EndDate || model.EndDate == null)).OrderByDescending(o => o.SaleDate).ToArray().Select(p => <b>MyMapper<SaleViewModel>.CopyObjProperties(p, "NumberIn1S,Total,SaleDate,Comments,Driver,GuidIn1S")</b>).ToList(); </p>

Need Your Help

Interstitial Ads in my project

java android libgdx interstitial

I followed this tutorial step by step, and I managed to put advertising banners, but do not get put Interstitial. enter link description here

JPA: Understanding the OneToOne bidirectional relationship

java jpa

I 'm trying to understand the possible way to use this relationship from the inverse side.