I would like to map an entity with a complex type to another entity. However, on the last line in the Main method a
System.NotSupportedException: Cannot compare elements of type 'ConsoleApplication2.ComplexType'. Only primitive types, enumeration types and entity types are supported.
exception is raised.
How to fix it?
I am aware I can flatten the complex type properties to the entity. However, it involves lots of code duplication so I strongly prefer a solution which does not need me to flatten the complex type properties to the entity. Complex types may themselves contain other complex types, so the solution should allow nesting complex types to complex types.
Entity Framework 6.1.3, AutoMapper 3.3.1 and 4.0.4, SQL Server 2014 SP1 Express, VS 2015, .NET 4.5.2 and 4.6.
It works if .SingleOrDefault(x => x.Id == 1) or .ProjectTo<MappedEntity>() is removed.
If still does not work if the .SingleOrDefault(x => x.Id == 1) is rewritten as .Where(x => x.Id == 1).ToList().SingleOrDefault();.
using System.Data.Entity;
using System.Linq;
using AutoMapper;
using AutoMapper.QueryableExtensions;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
Database.SetInitializer(new DropCreateDatabaseAlways<ClientContext>());
Mapper.CreateMap<Entity, MappedEntity>();
Mapper.CreateMap<ComplexType, MappedComplexType>();
var clientContext = new ClientContext();
clientContext.Set<Entity>().ProjectTo<MappedEntity>().SingleOrDefault(x => x.Id == 1);
}
}
class ClientContext : DbContext
{
public virtual DbSet<Entity> Entities { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Entity>().HasKey(x => x.Id);
modelBuilder.ComplexType<ComplexType>();
}
}
class Entity
{
public virtual int Id { get; set; }
public virtual ComplexType ComplexType { get; set; }
}
class ComplexType
{
public virtual string Field { get; set; }
}
class MappedEntity
{
public virtual int Id { get; set; }
public virtual MappedComplexType ComplexType { get; set; }
}
class MappedComplexType
{
public virtual string Field { get; set; }
}
}
StackOverflow: http://stackoverflow.com/questions/32995791/notsuportedexception-when-mapping-entities-with-complex-types-using-automapper-a
Project.To is probably trying to compare the class because when projecting it has to know if it's null or not as to set the property on the Mapped object to an instance of an object or to a null value. It has no concept of complex object and that the Complex Object is never going to be null so there's no need for a comparison.
I don't know how you can elegantly bypass the problem.
Perhaps trying ProjectUsing() might help, or flattening the object like you said.
For this particular case a workaround is
var entity = clientContext.Set<Entity>().SingleOrDefault(x1 => x1.Id == 1);
var mapped = Mapper.Map<MappedEntity>(entity);
@TylerCarlson1 Thanks, great tip. Even it is slightly more elegant than flattening I prefer this to flattering as at least the mapping model looks as expected. Unfortunately, Mapper.Map is not allowed inside the ResolveUsing, so it is still quite a lot of manually written and duplicated code so it significantly lowers the benefit of using AutoMapper. As such, I can confirm that ProjectUsing works as a workaround, even it is far from elegant.
@lbargaoanu Thanks, nice one. However, I would like to use the benefit of ProjectTo which optimizes the SQL queries so just the data needed to fill in MappedEntity. As there are several tables involved in the real application and some of the columns are binary blobs (which are not to be loaded in this particular mapping), the performance benefit seems quite significant.
@mcetkovsky Of course you can also not use complex types :)
@lbargaoanu Yeah, but it would mean really lot of meaningless duplications.
Is there a chance to get it working from the box or AutoMapper could not have enough info to even theoretically handle it?
AutoMapper cannot know what a complex type is. But you can tell it somehow that the type is not nullable and it could skip that check. You're welcome to try a pull request.
@mcetkovsky Another possible workaround:
Mapper.AllowNullDestinationValues = false;
I have the same error. I have replaced AutoMapper 4.2.1 by AutoMapper 5.0.0-beta-1 but it still fails.
// domain classes
public class Parent
{
public int ID { get; set; }
public string Name { get; set; }
public Body Body { get; set; }
}
[ComplexType]
public class Body
{
public Child Child1 { get; set; }
public Child Child2 { get; set; }
}
[ComplexType]
public class Child
{
public string Name { get; set; }
}
// Dtos
public class ParentDto
{
public int ID { get; set; }
public string Name { get; set; }
public Child Child1 { get; set; }
public Child Child2 { get; set; }
}
public class ChildDto
{
public string Name { get; set; }
}
// mapping configuration
CreateMap<Parent, ParentDto>()
.ForMember(dest => dest.Child1, opt => opt.MapFrom(origin => origin.Body.Child1))
.ForMember(dest => dest.Child2, opt => opt.MapFrom(origin => origin.Body.Child2))
CreateMap<Child, ChildDto>();
// service
IQueryable<Parent> parents = unitOfWork.ParentRepository.List();
return parents.ProjectTo<ParentDto>();
Do I have to add anything else to fix the error?
In your DTO, one way to fix it is to flatten your types. Don't do a child DTO, do this:
public class ParentDto
{
public int ID { get; set; }
public string Name { get; set; }
public string Child1Name { get; set; }
public string Child2Name { get; set; }
}
CreateMap<Parent, ParentDto>()
.ForMember(dest => dest.Child1Name, opt => opt.MapFrom(origin => origin.Body.Child1.Name))
.ForMember(dest => dest.Child2Name, opt => opt.MapFrom(origin => origin.Body.Child2.Name))
Your DTOs should be as flattened as possible, and only contain child DTO classes for things like child collections.
@jbogard, @lbargaoanu & @TylerCarlson1, have any of you made any progress with fixing this bug? It has been in the 4.2.0 milestone, the 5.0.0 milestone, and is now in the 5.1.0 milestone, so I am not sure how to gauge the progress at this point? As @mcetkovsky mentioned, complex types map fine for single result queries, but fail for collection result queries, so it would seem that the complex type mapping is working for the most part, but without the collection result queries we will be forced to eliminate complex types from our data mapping layer (and they are a great way to represent repetitive sub-data in a much more readable/usable fashion). I am just trying to see if someone is in the process of working on this bug, or if it is still on the backburner, so that we can decide how to move forward. Thanks for all your great work on this project!
@bmillspaugh I haven't, but I don't use Complex Types, so I have no need for this. Although looking at it again I think the exception message might be in EntityFramework and not AutoMapper. If that's the case then there's not much we can do much about it, since they probably didn't support Complex Types in their select statements.
Thing usually asked is can you make a select statement without AutoMapper to get the result you want? If you can't get that to work then AutoMapper can't solve this.
There is a fix slated to go into 5.1.0. (it's in the 5.1.0-alpha-01199 build on https://www.myget.org/F/automapperdev/api/v2 )
It is a problem with how automapper generates the expression, it will do a null check on the complex type, but entity framework doesn't support null checking of complex types.
The fix (using 5.1) looks like this:
CreateMap<Db.Something, Dto.Something>()
.ForMember(m => m.TheComplexType, opt => opt.AllowNull())
The .AllowNull() will skip the null checking.
HTH,
Ryan
Yea your right then it wouldn't be too hard to null check then, since 5.x uses expressions for regular mappings. Still don't plan on fixing it myself though.
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Most helpful comment
There is a fix slated to go into 5.1.0. (it's in the 5.1.0-alpha-01199 build on https://www.myget.org/F/automapperdev/api/v2 )
It is a problem with how automapper generates the expression, it will do a null check on the complex type, but entity framework doesn't support null checking of complex types.
The fix (using 5.1) looks like this:
The .AllowNull() will skip the null checking.
HTH,
Ryan