سؤال

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.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top