Как отобразить Integer в строку с помощью AutoMapper 3 и Entity Framework

Я пытаюсь использовать AutoMapper 3 для проецирования класса со свойством Integer на другой класс со свойством String.

Когда запрос выполняется, я получаю следующее исключение:

System.NotSupportedException: LINQ to Entities не распознает метод метода System.String ToString(), и этот метод нельзя преобразовать в выражение хранилища.

Вот соответствующие части кода:

public partial class Lookup
{
    public int LookupId { get; set; }
    public int LookupTypeId { get; set; }
    public string Value { get; set; }
    public int SequencialOrder { get; set; }

    public virtual LookupType LookupType { get; set; }
}

public class LookupProfile : Profile
{
    protected override void Configure()
    {
        CreateMap<Lookup, SelectListItem>()
            .ForMember(dest => dest.Value, opt => opt.MapFrom(src => src.LookupId.ToString()))
            .ForMember(dest => dest.Text, opt => opt.MapFrom(src => src.Value));

    }
}

И запрос выглядит так:

Provinces = _db.Lookups.Project().To<SelectListItem>().ToList()

Вопрос:

Есть ли способ, которым я мог бы настроить LookupProfile для правильного отображения и по-прежнему работать внутри Linq To Entities? Или есть другой способ заставить проекцию работать с Linq для Entities?

2 ответа

Решение

Решением было использование функции SqlFunctions.StringConvert.

Вот модифицированный код профиля, который заставил все работать:

public class LookupProfile : Profile
{
    protected override void Configure()
    {
        CreateMap<Lookup, SelectListItem>()
            .ForMember(dest => dest.Value, opt => opt.MapFrom(src => SqlFunctions.StringConvert((double)src.LookupId)))
            .ForMember(dest => dest.Text, opt => opt.MapFrom(src => src.Value));

    }
}

Я оставлю этот ответ здесь на случай, если кто-нибудь еще наткнется на ту же проблему, что и я.

Одна проблема с текущим принятым ответом состоит в том, что если вы работаете над проектом ASP.NET MVC, использующим проверку на стороне клиента с помощью помощников, вы получите ошибку проверки для поля идентификатора (если это число): The field [field] must be a number. Это происходит потому, что результат от SqlFunctions.StringConvert возвращает строку с несколькими начальными пробелами, поэтому ненавязчивый валидатор не видит ее как число.

Я решил эту проблему самостоятельно, чтобы создать общий SelectListItem<T> класс, который наследуется от SelectListItemскрывает оригинал Value собственность и реализует свою собственную Value сеттер:

public class SelectListItem<T> : SelectListItem
{
    public new T Value {
        set {
            base.Value = value.ToString();
        }
        // Kind of a hack that I had to add 
        // otherwise the code won't compile
        get {
            return default(T);
        }
    }
}

Затем в профиле Automapper я бы сопоставил элементы следующим образом:

public class LookupProfile : Profile
{
    protected override void Configure()
    {
        //Use whatever datatype is appropriate: decimal, int, short, etc
        CreateMap<Lookup, SelectListItem<int>>()
            .ForMember(dest => dest.Value, opt => opt.MapFrom(src => src.LookupId))
            .ForMember(dest => dest.Text, opt => opt.MapFrom(src => src.Value));

    }
}

И, наконец, на уровне Service, я бы отобразил сущности в общий класс и возвратил бы IEnumerable<SelectListItem>,

public IEnumerable<SelectListItem> GetList() {
    return _db.Lookups.Project().To<SelectListItem<int>>().ToList();
}

Таким образом, вы получите правильное значение для Value собственность без висячих пробелов.

Другие вопросы по тегам