在可查询的投影中如何使用AutoMapper将int映射到其枚举描述? [英] How to map an int to its enum description using AutoMapper during a queryable projection?

查看:603
本文介绍了在可查询的投影中如何使用AutoMapper将int映射到其枚举描述?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  public static string GetDescription(此枚举枚举)
{
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 {
[描述(N / A)]
无,
[描述(OPEN)]
打开,
[描述(CLOSED)]
关闭,
[描述(BAD CREDIT)
问题
}

这是目标对象:

  public class GetAccountResponse {
public int AccountId {get; set;}
public string Status {get; set;}
}

这是我尝试映射(使用最新的非静态自动版本版本)。记住这是在EF可查询投影期间。

  _config = new MapperConfiguration(cfg => cfg.CreateMap< Account,GetAccountsResponse>()
.ForMember dest => dest.Status,
opts => opts.MapFrom(src =>((AccountStatus)src.AccountStatusId).GetDescription())));

以下是查询是 IQueryable< Account>

  query.ProjectToList&GetEcountResponse>(_ config); 

这是我得到的例外:


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



解决方案

如果您会看到MapFrom方法的签名,您会注意到其中一个重载采用类型为 Expression< Func< TSource,TMember>> 的参数。 p>

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



这里是一个仅使用枚举名称的示例:您应该可以直接适应使用您的描述:

  public static class EnumerableExpressionHelper 
{
public static Expression< Func< TSource ,String>>> CreateEnumToStringExpression< TSource,TMember>(
表达式&FunC< TSource,TMember>> memberAccess,string defaultValue =)
{
var type = typeof(TMember);
if(!type.IsEnum)
{
throw new InvalidOperationException(TMember必须是枚举类型);
}

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
返回表达式;
}
}

您将使用它如下:

  CreateMap< Entry,EntryListItem>()
.ForMember(e => e.ReviewStatus,
c => c.MapFrom(EnumerableExpressionHelper.CreateEnumToStringExpression((Entry e)=> e.ReviewStatus)))


Here is the enum extension method to get its description attribute.

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;
}

Here is the source object:

public class Account {
    public int AccountId {get;set;}
    public int AccountStatusId {get;set;}
}

Here is the enum:

public enum AccountStatus {
    [Description("N/A")]
    None,
    [Description("OPEN")]
    Open,
    [Description("CLOSED")]
    Closed,
    [Description("BAD CREDIT")
    Problem
}

Here is the destination object:

public class GetAccountResponse {
    public int AccountId {get;set;}
    public string Status {get;set;}
}

Here is my attempt to map (using the latest non-static automapper version). Remember this is during an EF queryable projection.

_config = new MapperConfiguration(cfg => cfg.CreateMap<Account, GetAccountsResponse>()
    .ForMember(dest => dest.Status,
        opts => opts.MapFrom(src => ((AccountStatus) src.AccountStatusId).GetDescription())));

Here is the projection where query is an IQueryable<Account>:

query.ProjectToList<GetAccountResponse>(_config);

This is the exception I get:

Can't resolve this to Queryable Expression

解决方案

If you check out the signature of the MapFrom method, you'll notice that one of the overloads takes a parameter of type Expression<Func<TSource, TMember>>.

This suggests that you could write a method which builds an expression tree from ternary expressions that can convert any possible value of your enum to its appropriate string. AutoMapper would then convert this into the appropriate SQL expression via LINQ.

Here's an example which just uses the Enum names themselves: you should be able to adapt it straightforwardly to use your Descriptions:

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;
    }
}

You would use it as follows:

CreateMap<Entry, EntryListItem>()
            .ForMember(e => e.ReviewStatus,
                c => c.MapFrom(EnumerableExpressionHelper.CreateEnumToStringExpression((Entry e) => e.ReviewStatus)))

这篇关于在可查询的投影中如何使用AutoMapper将int映射到其枚举描述?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆