DaGeek
DaGeek

Reputation: 43

Automapper Project using

I am currently using automapper in my backend to map objects to models. I recently decided to use the following code to handle all my timezone conversions:

  cfg.CreateMap<DateTime?, DateTime?>()
  .ProjectUsing(i => DbFunctions.AddHours(i, offset.Hours));

  cfg.CreateMap<DateTime, DateTime>()
  .ProjectUsing(i => DbFunctions.AddHours(i, offset.Hours).Value);


  Object.ProjectTo<ObjectModel>().SingleOrDefault();

then it works fine and the object is mapped and timezone converted

However when i am using the following code in my business layer to do a single object mapping:

Mapper.Map<Object, ObjectModel>(singleRecord); 

It Gives an error : This function can only be invoked from LINQ to Entities.

stack trace :

at System.Data.Entity.DbFunctions.AddHours(Nullable`1 timeValue, Nullable`1 addValue)
   at lambda_method(Closure , DateTime , DateTime , ResolutionContext )
   at AutoMapper.ResolutionContext.Map[TSource,TDestination](TSource source, TDestination destination)
   at lambda_method(Closure , Inventory , InventoryModel , ResolutionContext )

Mapper.Map is important to use in specific scenarios and i also don't want to project single records.

is there a way round this ?

Upvotes: 4

Views: 3996

Answers (2)

Ivan Stoev
Ivan Stoev

Reputation: 205569

By default AutoMapper will build a mapping Func<TSource, TDestination>> to be used by Map method by compiling the Expression<TFunc<TSource, TDestionation>> passed to ProjectUsing and used by ProjectTo, because usually it's enough and works. But not with EF canonical functions.

You could override that behavior by specifying a different conversion to be used with Map method by providing explicitly both ProjectUsing and ConvertUsing:

var map1 = cfg.CreateMap<DateTime?, DateTime?>();
map1.ProjectUsing(i => DbFunctions.AddHours(i, offset.Hours));
map1.ConvertUsing(i => i?.AddHours(offset.Hours));

var map2 = cfg.CreateMap<DateTime, DateTime>();
map2.ProjectUsing(i => DbFunctions.AddHours(i, offset.Hours).Value);
map2.ConvertUsing(i => i.AddHours(offset.Hours));

Upvotes: 2

Hintham
Hintham

Reputation: 1086

From MSDN:

Provides common language runtime (CLR) methods that expose EDM canonical >functions for use in DbContext or ObjectContext LINQ to Entities queries.

So the error is to be expected because the projection is not executed in a LINQ to Entities query.

The DbFuncions.AddHours() call is translated to a database function. Since in your business layer you're not passing an entity but an object, the error is thrown.

You have two ways to work around the problem: 1. Use a different mapping logic in your bussiness layer. 2. Use a mapping logic that does not depend on the DbFunctions class so that it can be used in your DAL and business layer.

Upvotes: 1

Related Questions