I have an object graph that I'm loading from a database using EF CodeFirst and AutoMapper into DTOs:-
public class Foo
{
public int Id { get; set; }
public virtual ICollection<Bar> Bars { get; set; }
}
public class Bar
{
public int Id { get; set; }
public int FooId { get; set; }
public virtual Foo Foo { get; set; }
public string Name { get; set; }
public int SortOrder { get; set; }
}
public class FooDto
{
public IEnumerable<BarDto> Bars { get; set; }
}
public class BarDto
{
public string Name { get; set; }
public int SortOrder { get; set; }
}
My mappings look like:-
mapper.CreateMap<Foo, FooDto>();
mapper.CreateMap<Bar, BarDto>();
So far, so good. I can grab the entities from my context and project to the DTO nicely:-
var foos = context.Foos.Project().To<FooDto>();
What I can't do with this approach, however, is sort the Bars
by their SortOrder
inside the IQueryable.
If I try:-
mapper.CreateMap<Foo, FooDto>()
.ForMember(
x => x.Bars
opt => opt.MapFrom(src => src.Bars.OrderBy(x => x.SortOrder)));
mapper.CreateMap<Bar, BarDto>();
var foos = context.Foos.Project().To<FooDto>();
I get an exception:-
System.InvalidOperationException: Sequence contains no elements
at System.Linq.Enumerable.First[TSource](IEnumerable`1 source)
at AutoMapper.MappingEngine.CreateMapExpression(Type typeIn, Type typeOut)
...
Seems this is related to https://github.com/AutoMapper/AutoMapper/issues/159 - though I'm already using a complex type for the child collection. I guess CreateMapExpression doesn't support OrderBy on child collections?
If I'm not using .Project().To() then I can sort the child collection easily:-
var model = context.Foos.Select(x => new FooDto()
{
Bars = x.Bars.OrderBy(y => y.SortOrder)
});
but then I have to repeat the mapping wherever I want to use it, defeating the purpose of using AutoMapper.
Curiously:-
1) I can perform other (more complicated?) operations on the child collection and flatten those into my parent DTO no problem:-
mapper.CreateMap<Foo, FooDto>()
.ForMember(
x => x.AllBarsHaveAName,
opt => opt.MapFrom(src =>
src.Bars.All(x => x.Name != null)));
2) I can Mapper.Map<FooDto>(foo);
in memory just fine, and it'll sort the bars no problem.
It's possible to sort the child collection at the IQueryable level while still using .Project().To()?
If you have to do complex mapping behavior, it might be better to avoid using AutoMapper for that scenario. Reverse mapping can get very complicated very quickly, and unless it's very simple, you can have business logic showing up in mapping configuration.
Polymorphic element types in collectionsAutoMapper supports polymorphic arrays and collections, such that derived source/destination types are used if found.
AutoMapper in C# is a library used to map data from one object to another. It acts as a mapper between two objects and transforms one object type into another. It converts the input object of one type to the output object of another type until the latter type follows or maintains the conventions of AutoMapper.
AutoMapper is an object-object mapper that allows you to solve the problem of manually mapping each property of a class with the same properties of another class. Before AutoMapper was introduced if we wanted to assign one object property to another object property then we were following a long procedure.
Ended up modifying the AutoMapper source code to support this scenario. Hopefully the proposed fix will be accepted, but in the meantime you can see the details at:-
https://github.com/AutoMapper/AutoMapper/pull/327
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With