AutoMapper/AutoMapper.Extensions.ExpressionMapping

AutoMapper: Expression mapping with flattening in collection

flobernd opened this issue · 3 comments

Hey there,

I'm currently playing around with Automapper.Expressions.ExpressionMapping and stumbled across an issue. These are the involved classes of my problematic entity:

public class MyDto
{
    public Guid Id { get; set; }
    public ICollection<string> Tags { get; set; }
}

public class MyEntity
{
    public Guid Id { get; set; }
    public ICollection<MyEntityTag> Tags { get; set; } // <- one-to-many relation
}

public class MyEntityTag
{
    public Guid Id { get; set; }
    public string Tag { get; set; }
}

As you see, the Tags collection from the entity is flattened from an object collection to just a string collection. For object mapping this works fine.

When using expression mapping and using the resulting expression with EntityFramework the following works as well:

x => x.Where(x => x.Tags.Any())

Sadly, the following does not work:

// Boolean Contains(System.String) can not be called with an instance of type MyEntityTag
x => x.Where(x => x.Tags.Contains("test"))

// Binary operator Equal is not defined for MyEntityTag and System.String
x => x.Where(x => x.Tags.Any(x => x == "test"))

I ofc understand what's going on, but I'm wondering if there is a way to tell AutoMapper how to correctly translate the expressions.

Best regards

You haven't included your configuration so hard to tell.
x => x.Where(x => x.Tags.Any(x => x == "test")) should work with the following:

CreateMap<MyEntity, MyDto>()
                .ForMember(dest => dest.Tags, opts => opts.MapFrom(src => src.Tags.Select(et => et.Tag)));

x => x.Where(x => x.Tags.Contains("test")) needs the ToList() to map the expression. i.e.

CreateMap<MyEntity, MyDto>()
                .ForMember(dest => dest.Tags, opts => opts.MapFrom(src => src.Tags.Select(et => et.Tag).ToList()));

Or x => x.Where(x => x.Tags.Contains<string>("test")) without ToList() to get IEnumerable<string>.Contains().

Thanks for the fast reply!

You are right, I forgot to add my configuration - your first example looks pretty similar to my config. I will test again (especially with the additional .ToList()) and reply back to you afterwards. If it's still not working I will construct a PoC configuration and include it in my response as well.

The .ToList() makes the difference! Works like a charm now. Thanks again.