Reputation: 79
I am getting the error only when I am using ProjectTo, I could not understand the underlying issue. (Automapper version am using 4.2.1.0) "The specified type member 'Tags' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported." We could do this manipulation in DTO as well, but I should stick to doing the manipulation in entity side only. Do let me know the ways or work around I could handle this without upgrading the version. TIA I want the computed value of Tags property of entity needs to be mapped to the Tags property of the DTO, but this works fine when I am doing the normal way.
Source/destination types
public class Template : IEntity<int>
{
public string Name { get; set; }
public int Id { get; set; }
public string _Tags { get; set; }
[NotMapped]
public List<string> Tags
{
get { return _Tags == null ? null : JsonConvert.DeserializeObject<List<string>>(_Tags); }
set { _Tags = JsonConvert.SerializeObject(value); }
}
}
Entity Config
internal sealed class TemplateConfig : EntityTypeConfiguration<Template>
{
public TemplateConfig()
{
Ignore(x => x.Tags);
HasKey(x => x.Id)
.Map(m =>
{
m.ToTable("Template");
m.Property(x => x.Id).HasColumnName("ID");
m.Property(x => x.Name).HasColumnName("Name");
m.Property(x => x._Tags).HasColumnName("Tags");
});
}
}
Destination DTO:
public class Template
{
public int Id { get; set; }
public string Name { get; set; }
public List<string> Tags { get; set; }
}
Mapping configuration
Mapper.CreateMap<Template, DTO.Template>();
Mapper.CreateMap<DTO.Template, Template>();
//These are just for information, but getting error only when using ProjectTo. (Ignore about the OData thing)
public virtual async Task<IQueryable<TDto>> Get(ODataQueryOptions<TDto> query)
{
try
{
var expands = query.GetExpandedPropertyNames();
//Assume the collection has the data from db
var test = Collection.ToList();
//getting the exception here
return await Collection.ProjectTo<TDto>(null, expands).AsTask();
}
catch(Exception ex)
{
throw ex;
}
}
//Controller method
public override async Task<IQueryable<Template>> Get(ODataQueryOptions<Template> query)
{
try
{
List<Template> result = (await base.Get(query)).ToList();
return result.AsEnumerable().AsQueryable();
}
catch(Exception ex)
{
throw ex;
}
}
Upvotes: 2
Views: 3443
Reputation: 930
This is happening because .ProjectTo<>(...)
is building the select statement for you in SQL. As .Tags
maps between your objects, it is being included in the select statement, and then entity framework is complaining that it can't do that (because of the NotMapped
attribute).
Instead of using ProjectTo<>(...)
you could just use a normal .ToList()
and then use .Select(Mapper.Map<TDto>)
or Mapper.Map<List<TDto>>(list)
.
That should work, as entity framework will populate your Tags field from the string field, and automapper can do the map ok.
public virtual async Task<IQueryable<TDto>> Get(ODataQueryOptions<TDto> query)
{
try
{
var expands = query.GetExpandedPropertyNames();
//Assume the collection has the data from db
var test = Collection.ToList();
var entities = expands.ToList();
// you can either use .Select to project using LINQ
var dtos = await entities.Select(Mapper.Map<TDto>).AsTask();
// or you can use Mapper.Map to a list of entities.
dtos = await Mapper.Map<List<TDto>>(entities).AsTask();
return dtos;
}
catch(Exception ex)
{
// side note, don't throw ex, you'll lose the stack trace
throw;
}
}
Upvotes: 4
Reputation: 3591
Have you tried implementing the ignore in the MappingConfiguration? I can't quite tell which direction you're having issues with, but something like:
Mapper.CreateMap<Template, DTO.Template>()
.ForMember(dest => dest.Tags, opts => opts.Ignore());
Upvotes: 0