I'm trying to project from my Order
model to my OrderDTO
model. Order
has an enum. The problem is that projection doesn't work if I try to to get the Description attribute from the Enum. Here it's my code:
OrderStatus.cs:
public enum OrderStatus {
[Description("Paid")]
Paid,
[Description("Processing")]
InProcess,
[Description("Delivered")]
Sent
}
Order.cs:
public class Order {
public int Id { get; set; }
public List<OrderLine> OrderLines { get; set; }
public OrderStatus Status { get; set; }
}
OrderDTO.cs:
public class OrderDTO {
public int Id { get; set; }
public List<OrderLineDTO> OrderLines { get; set; }
public string Status { get; set; }
}
With this following configuration in my AutoMapper.cs:
cfg.CreateMap<Order, OrderDTO>().ForMember(
dest => dest.Status,
opt => opt.MapFrom(src => src.Status.ToString())
);
Projection works, but I get an OrderDTO object like this:
- Id: 1
- OrderLines: List<OrderLines>
- Sent //I want "Delivered"!
I don't want Status
property to be "Sent", I want it to be as its associated Description attribute, in this case, "Delivered".
I have tried two solutions and none of them have worked:
ResolveUsing is not supported for projections, see the wiki on LINQ projections for supported operations.
Using a static method to return the Description attribute in String by Reflection.
cfg.CreateMap<Order, OrderDTO>().ForMember(
dest => dest.Status,
opt => opt.MapFrom(src => EnumHelper<OrderStatus>.GetEnumDescription(src.Status.ToString()))
);
But this gives me the following error:
LINQ to Entities does not recognize the method 'System.String GetEnumDescription(System.String)' method, and this method cannot be translated into a store expression.
Then, how can I achieve this?
You can add an extension method like this one (borrowed the logic from this post):
public static class ExtensionMethods
{
static public string GetDescription(this OrderStatus This)
{
var type = typeof(OrderStatus);
var memInfo = type.GetMember(This.ToString());
var attributes = memInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
return ((DescriptionAttribute)attributes[0]).Description;
}
}
Then access it in your map:
cfg =>
{
cfg.CreateMap<Order, OrderDTO>()
.ForMember
(
dest => dest.Status,
opt => opt.MapFrom
(
src => src.Status.GetDescription()
)
);
}
This results in what you are asking for:
Console.WriteLine(dto.Status); //"Delivered", not "sent"
See a working example on DotNetFiddle
Edit1: Don’t think you can add a local look up function like that to LINQ to entities. It would only work in LINQ to objects. The solution you should pursue perhaps is a domain table in the database that allows you to join to it and return the column that you want so that you don’t have to do anything with AutoMapper.