Как отобразить 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
собственность без висячих пробелов.