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 ?
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));
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With