I am trying to use AutoMapper 3 to project a class with an Integer property to another class with a String property.
When the query is executed then I get the following exception:
System.NotSupportedException: LINQ to Entities does not recognize the method 'System.String ToString()' method, and this method cannot be translated into a store expression.
Here are the relevant parts of the code:
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));
}
}
And the query looks like:
Provinces = _db.Lookups.Project().To<SelectListItem>().ToList()
Question:
Is there a way I could configure the LookupProfile to do the proper mapping and still work inside Linq To Entities? Or is there another way I could make the projection work with Linq to Entities?
The solution was to use the SqlFunctions.StringConvert function.
Here is the modified profile code that made everything work:
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));
}
}
I'll leave this answer here in case anyone else stumbles upon the same issue I had.
One problem with the current accepted answer is that if you're on an ASP.NET MVC project using client-side validation through helpers, you'll get a validation error for the ID field (if it's a number): The field [field] must be a number.
That happens because the result from SqlFunctions.StringConvert
returns a string with several leading spaces, so the unobtrusive validator doesn't see it as a number.
The way I solved this issue on my own was to create a generic SelectListItem<T>
class that inherits from SelectListItem
, hides the original Value
property and implements its own Value
setter:
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);
}
}
}
Then on the Automapper profile I would map the items like so:
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));
}
}
And finally on the Service layer, I would map the entities to the generic class and return an IEnumerable<SelectListItem>
.
public IEnumerable<SelectListItem> GetList() {
return _db.Lookups.Project().To<SelectListItem<int>>().ToList();
}
This way you'll get the right value for the Value
property without trailing spaces.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.