Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AutoMapper IQueryable Extension throws "Cannot compare elements of type <Complex Type>" with

AutoMapper IQueryable Extension's Project().To<TViewModel>().SingleOrDefault() throws this exception:

Cannot compare elements of type 'App.Domain.MyComplexType. Only primitive types, enumeration types and entity types are supported.

I have this model:

public class MyEntityType  // this is an entity type on the dbContext
{
   public int Id {get;set;
   public MyComplexType MyComplexType {get;set;}
}

public class MyComplexType // this is a complex type
{
    public decimal Property1 { get; set;}
    public string Property2 { get;set;}
}

public class ViewModel
{
public int Id { get;set;}
public decimal MyComplexTypeProperty1 { get;set;}
}

I use AutoMapper to configure mapping from IQueryable<MyEntityType> to ViewModel:

Mapper.CreateMap<MyEntityType, MyComplexType>(); // I rely on AutoMapper's 
//convention for flattening `source.MyComplexType.Property1` to `dest.MyComplexTypeProperty1'

Then I try to retrieve a single item like this:

var myItem = myContext.Where(x => x.Id == id).Project().To<ViewModel>().SingleOrDefault();

I get the above exception when SingleOrDefault() is called, so apparently

I currently work around this by first calling SingleOrDefault() and then doing the mapping, this works:

var myItem = Mapper.Map<ViewModel>(myContext.Find(id));

Other posts basically say that the error above arises when trying to compare a EF Complex Type with null, as, e.g., in a Where clause, but that is apparently not the case here.

like image 324
AunAun Avatar asked May 12 '15 17:05

AunAun


2 Answers

LINQ to entities is unable to perform compare (null check) for complex types as you suggested. For example this does not work...

myContext.Select(i => new
{
    MyComplexType = i.MyComplexType != null ? 
        new MyComplexTypeViewModel() 
        {  
           Property1 = i.MyComplexType.Property1
        }
        : null
})

By default Automapper tries to map null source values as nulls and sometimes adds similar conditions in generated expression when using Project().To<>() or Mapper.Engine.CreateMapExpression<,>().

In my case i was mapping whole complex type to it's own viewmodel and did not use property flattening. This configuration value solved the issue for me...

Mapper.AllowNullDestinationValues = false;

You may try to manually create mapping expression using CreateMapExpression<TSource,TDest>() and look for null checks on complex type to see if it's the same situation.

like image 187
Tomas Dolezal Avatar answered Sep 20 '22 03:09

Tomas Dolezal


make your prop Nullable

public decimal? MyComplexTypeProperty1 { get;set; }

then use this mapping

Mapper.CreateMap<MyEntityType, MyComplexType>()
    .ForMember(p => p.MyComplexTypeProperty1, p => p.AllowNull())

and if you want solve problems for all complex types, then you can use this code in creating MapperConfiguration

var config = new MapperConfiguration(cfg =>
{
    cfg.ForAllPropertyMaps(p =>
        p.SourceType == typeof(MyComplexType) ||
        p.SourceType == typeof(AnotherComplexType) // || ...

        //NOTE: if you have another ComplexTypes so remove prev lines
        //      and use this line to handle all of them
        //p.SourceType.GetCustomAttributes(typeof(ComplexType))

        (p, q) => { q.AllowNull(); }
    );

    //other configs
});
like image 33
Omid-RH Avatar answered Sep 23 '22 03:09

Omid-RH