Enums 如何在可查询投影期间使用AutoMapper将int映射到其枚举描述?

Enums 如何在可查询投影期间使用AutoMapper将int映射到其枚举描述?,enums,entity-framework-6,automapper,iqueryable,automapper-4,Enums,Entity Framework 6,Automapper,Iqueryable,Automapper 4,下面是获取其description属性的枚举扩展方法 public static string GetDescription(this Enum enumeration) { if (enumeration == null) throw new ArgumentNullException(); var value = enumeration.ToString(); var type = enumeration.GetType(); var des

下面是获取其description属性的枚举扩展方法

public static string GetDescription(this Enum enumeration)
{
    if (enumeration == null)
        throw new ArgumentNullException();

    var value = enumeration.ToString();
    var type = enumeration.GetType();
    var descriptionAttribute =
        (DescriptionAttribute[]) type.GetField(value).GetCustomAttributes(typeof (DescriptionAttribute), false);

    return descriptionAttribute.Length > 0 ? descriptionAttribute[0].Description : value;
}
以下是源对象:

public class Account {
    public int AccountId {get;set;}
    public int AccountStatusId {get;set;}
}
以下是枚举:

public enum AccountStatus {
    [Description("N/A")]
    None,
    [Description("OPEN")]
    Open,
    [Description("CLOSED")]
    Closed,
    [Description("BAD CREDIT")
    Problem
}
以下是目标对象:

public class GetAccountResponse {
    public int AccountId {get;set;}
    public string Status {get;set;}
}
下面是我的映射尝试(使用最新的非静态automapper版本)。请记住,这是在EF可查询投影期间

_config = new MapperConfiguration(cfg => cfg.CreateMap<Account, GetAccountsResponse>()
    .ForMember(dest => dest.Status,
        opts => opts.MapFrom(src => ((AccountStatus) src.AccountStatusId).GetDescription())));
\u config=new-MapperConfiguration(cfg=>cfg.CreateMap()
.FormMember(目标=>目标状态,
opts=>opts.MapFrom(src=>((AccountStatus)src.AccountStatusId.GetDescription());
这是一个投影,其中查询是一个
IQueryable

query.ProjectToList(\u config);
这是我得到的例外:

无法将此解析为可查询表达式


如果您签出MapFrom方法的签名,您会注意到其中一个重载采用
Expression
类型的参数

这表明您可以编写一个方法,从三元表达式构建表达式树,该表达式可以将枚举的任何可能值转换为相应的字符串。然后,AutoMapper将通过LINQ将其转换为适当的SQL表达式

下面是一个仅使用枚举名称本身的示例:您应该能够直接调整它以使用您的描述:

公共静态类EnumerableExpressionHelper
{
公共静态表达式CreateEnumToString表达式(
表达式memberAccess,字符串defaultValue=“”)
{
变量类型=类型(t成员);
如果(!type.IsEnum)
{
抛出新的InvalidOperationException(“TMember必须是枚举类型”);
}
var enumNames=Enum.GetNames(类型);
var enumValues=(TMember[])Enum.GetValues(类型);
var inner=(表达式)Expression.Constant(defaultValue);
var参数=memberAccess.Parameters[0];
for(int i=0;i
您将按如下方式使用它:

CreateMap<Entry, EntryListItem>()
            .ForMember(e => e.ReviewStatus,
                c => c.MapFrom(EnumerableExpressionHelper.CreateEnumToStringExpression((Entry e) => e.ReviewStatus)))
CreateMap()
.FormMember(e=>e.ReviewStatus,
c=>c.MapFrom(EnumerableExpressionHelper.CreateEnumToString表达式((条目e=>e.ReviewStatus)))

这看起来棒极了,但不幸的是,我不太出色的表达技巧让我有点紧张。我不理解您传递给方法的参数,特别是
(条目e)=>e.ReviewStatus))
Entry
枚举类型吗?@ChadRichardson Entry在本例中是实体,ReviewStatus是条目上的属性,它是枚举类型。因此,整个表达式的作用是将条目上的ReviewStatus属性转换为字符串并存储在EntryListItem上的ReviewStatus属性中。对于像我这样的其他人,由于源(数据库字段)不是枚举类型,因此在将其传递给此表达式方法时,需要将其强制转换为一
.ForMember(e=>e.ShippingContainerHeaderStatusDesc,c=>c.MapFrom(CommonBusinessObjects.ViewModelMaps.AutoMapperExtensions.CreateEnumToString Expression((ShippingContainerDetail e)=>(ShippingContainerHeader.StatusOptions)e.ShippingContainerHeader.StatusId))
。将数据库列(
ShippingContainerStatus.StatusId
an
int
)的大小写记到类型为
ShippingContainerHeader.StatusOptions
public static class EnumerableExpressionHelper
{
    public static Expression<Func<TSource, String>> CreateEnumToStringExpression<TSource, TMember>(
        Expression<Func<TSource, TMember>> memberAccess, 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;
    }
}
CreateMap<Entry, EntryListItem>()
            .ForMember(e => e.ReviewStatus,
                c => c.MapFrom(EnumerableExpressionHelper.CreateEnumToStringExpression((Entry e) => e.ReviewStatus)))