AutoMapper / AutoMapper.Extensions.ExpressionMapping

MIT License
143 stars 39 forks source link

Issues with enum to string mapping in expressions #145

Closed Johkie closed 2 years ago

Johkie commented 2 years ago

Versions

Setup

Hi, I've got the following objects (quite simplified but still)

public enum CountryA3
{
    AFG = 0,
    ALA = 1,
    ....
}

public class TestDto 
{
    public CountryA3 Country { get; set; }
}

public class TestModel
{
    public string Country { get; set; }
}

With the following map configuration (works as intended while mapping between plain TestDto <-> TestModel objects)

CreateMap<TestModel, TestDto>()
    .ForMember(d => d.Country, opt => opt.MapFrom(s => Enum.Parse<CountryA3>(s.Country)));
CreateMap<TestDto, TestModel>()
    .ForMember(d => d.Country, opt => opt.MapFrom(s => s.Country.ToString()));

Issue

I am currently required to save the value of the enum as a string in an SQL database while making the TestDto querable from an API endpoint. The query is translated dynamically in a custom resolver that generates an expression based upon a specified class. In this case the expression is built upon TestDto since the model isn't exposed to the API. The result may looks like this.

Expression<Func<TestDto, bool>> expression = x => (x.Country == AFG)
//  x => (x.Country == AFG) 

This is where things get complicated, because when I map the expression to the TestModel, I get the following result

var exp = _mapper.Map<Expression<Func<TestModel, bool>>>(expression);
// Result:  x => (Parse(x.Country) == AFG)

Automapper itself is happy, but I've ended up with an expression that can't be translated by EFCore in my where clause that generates the following exception.

The LINQ expression 'DbSet<TestModel>()
    .Where(s => Enum.Parse<CountryA3>(s.Country) == AFG)' could not be translated. 
Additional information: Translation of method 'System.Enum.Parse' failed

Is there any way I can get the mapper to give me a result that is readable for EFCore? Since the expression mapping seems to be using the Model -> Dto mapper in this case, I'm not really sure how to specify that I want to work with string comparing instead of using the enum (like the Dto -> Model map).

I've become quite desperate so any guidance to what I can do would be very much appreciated. Thanks!

BlaiseD commented 2 years ago

An expression like this or a DbFunction (if one exists) to perform the parse should work - really an EF problem.