0

I'd like to streamline my current view model mapping. I currently use Automapper ProjectTo to create my view model, then call a post mapping method to populate a StatusDescription string property from a Status enum whose value is in another int property in the view model class, StatusId.

I found this other answer, but I am not able to get it to work, and am having a hard time understanding what exactly it is doing due to my general lack of experience with expressions.

For reference, here is the expression method (note I had to comment out the defaultValue parameter as I was getting an error An expression tree may not contain a call or invocation that uses optional arguments:

public static Expression<Func<TSource, String>> CreateEnumToStringExpression<TSource, TMember>(
    Expression<Func<TSource, TMember>> memberAccess)//,string defaultValue = ""
{
    string defaultValue = "";
    var type = typeof(TMember);
    if (!type.IsEnum)
    {
        throw new InvalidOperationException("TMember must be an Enum type");
    }

    var enumNames = Enum.GetNames(type);
    var enumValues = (TMember[])Enum.GetValues(type);

    var inner = (Expression)Expression.Constant(defaultValue);

    var parameter = memberAccess.Parameters[0];

    for (int i = 0; i < enumValues.Length; i++)
    {
        inner = Expression.Condition(
        Expression.Equal(memberAccess.Body, Expression.Constant(enumValues[i])),
        Expression.Constant(enumNames[i]),
        inner);
    }

    var expression = Expression.Lambda<Func<TSource, string>>(inner, parameter);

    return expression;
}

I am calling it like this:

.ForMember(dest => dest.Status, option =>
    option.MapFrom(src =>
        EnumHelper.ExpressionHelper
        .CreateEnumToStringExpression((ShippingContainerHeader s) => s.StatusId)
    ))

The error I am getting when I run this is: LINQ to Entities does not recognize the method 'System.String ToString()' method, and this method cannot be translated into a store expression..

A.) I think I am calling this wrong maybe? Shouldn't I be using the reference to src in the MapFrom method call in order to pass the actual value of StatusId to the expression method?

B.) Seems like there is an issue with the expression generation method as it is producing the ToString() error. There is not an explicit .ToString() call in that method, but it must be implied somehow.

C.) Understanding the code: I can follow all of the code within the CreateEnumToStringExpression method except what the parameter variable is and the final expression variable expression statement. Also the generic types I'm confused on...there are a lot of generic types and the call to the method from the linked example doesn't explicitly define any of them.

In Expression<Func<TSource, String>> I'm pretty sure TSource is the input, which is an int. String is the output, which would be the enum name.

In CreateEnumToStringExpression<TSource, TMember> and Expression<Func<TSource, TMember>> memberAccess: TSource again is int, TMember is the enum class type.

But do you not have to explicitly call these out when calling the method? Something like: CreateEnumToStringExpression<int, StatusesEnum>(new Expression<Func<int, ShippingContainerHeader>> { s => s.StatusId })

crichavin
  • 4,672
  • 10
  • 50
  • 95
  • This isn't merely a cast? – Robert Harvey May 16 '19 at 16:24
  • In any case, the error message is speaking absolute truth. LINQ to Entities does not recognize the method 'System.String ToString()' method, and this method cannot be translated into a store expression. – Robert Harvey May 16 '19 at 16:25
  • @RobertHarvey yes, I just changed the expression to remove the `src =>` like in the linked to answer. That assignment was calling a `ToString()`. Now I get `ShippingContainerHeader` is not an enum, so I changed it to `StatusesEnum`, but now the `=> s.StatusId` is no longer valid...as `s` is referring to the enum type, not the source data type. Not sure what to do from here. – crichavin May 16 '19 at 16:29
  • @RobertHarvey a simple cast does not work either...it also gives the `LINQ to Entities does not recognize the method 'System.String ToString()' method, and this method cannot be translated into a store expression..` error. – crichavin May 16 '19 at 16:34
  • All providers I've used recognized methods in the `Convert` class. Try using `Convert.ToString()`. – Jeff Mercado May 16 '19 at 20:34
  • Check [the execution plan](https://docs.automapper.org/en/latest/Understanding-your-mapping.html). That will show where that ToString is coming from. `Object.ToString` might make sense. But `String.ToString`? – Lucian Bargaoanu May 17 '19 at 04:59

0 Answers0